您现在的位置是:首页 >技术教程 >吃透 Spring AOP (2.底层原理)网站首页技术教程
吃透 Spring AOP (2.底层原理)
实践
吃透 Spring AOP (1.理解概念)
1中讲了很多理解和概念。包括动态代理代理的思想。这里我们针对jdk动态代理先来点代码实践,动手的过程中体会它的设计原理
首先我们来个最简单的接口和实现类:
public class JdkProxyDemo {
interface Foo{
void foo();
}
class Target implements Foo{
@Override
public void foo() {
System.out.println("目标对象方法调用");
}
}
public static void main(String[] args) {
}
}
然后我们开始动态创建代理对象:
首先思路我们已经在上一篇里面说明白了。我们一点点按照思路来:
首先我们既然时为 Target 创建代理对象。
那么代理对象从哪里来? java中提供了一个创建代理对象实例的类和方法
Proxy.newProxyInstance
ClassLoader loader = JdkProxyDemo.class.getClassLoader();
Foo proxyInstance = (Foo)Proxy.newProxyInstance(loader, new Class[]{Foo.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
这个方法有三个参数:
-
定义代理类接口的类加载器(不理解这个概念的看文末)
-
代理类实现的接口列表(注意是个列表 因为被代理类可能实现了多个接口)(这里就看出来了 jdk动态代理为什么必须实现接口,因为这里生成代理类的时候只能传接口)
-
然后调用分派的一个类 在这个类里面 就封装具体的代理增强操作
ok我们把当前类的类加载器获取到。 然后把接口类Foo放进去,再new一个InvocationHandler 里面是一个匿名内部类的形式我们可以干我们相干的具体代理操作, 然后我们先不做具体的代理 先运行一下 调一下我们刚刚生成的代理对象的方法:
public static void main(String[] args) {
ClassLoader loader = JdkProxyDemo.class.getClassLoader();
Foo proxyInstance = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before....");
return null;
}
});
proxyInstance.foo();
}
before....
Process finished with exit code 0
完工之后 说明没问题。 现在我们创建了目标对象的代理对象。但是这个代理对象 还没有具体的对这个目标对象做什么增强了,它只是刚刚出生而已。
接着:
public static void main(String[] args) {
Target target = new Target();
ClassLoader loader = JdkProxyDemo.class.getClassLoader();
Foo proxyInstance = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("对擎天柱进行前置武器增强");
method.invoke(target,args);
System.out.println("对擎天柱进行后置武器增强");
return null;
}
});
proxyInstance.foo();
}
在invoke方法中 我们通过反射 调用目标对象target的foo方法。 然后对它进行增强。
然后就可以调用代理类的方法了。
对擎天柱进行前置武器增强
原始擎天柱
对擎天柱进行后置武器增强
Process finished with exit code 0
这个代理类 它相当于包裹主了 被代理类 然后对它进行前后加工。
这里注意 因为我们的foo()是个void 也没有参数,
如果有返回有参数的话。 就return method方法的结果就好了。
这就是JDK动态代理的基本原理
只不过这个过程中上面这些类名方法名我们是现成往里写,spring它会在你配置了aop之后通过注解或者其他方式 获取到:
你的代理类名是什么? 获取到它 然后使用类加载器 生成一个参数
你的代理对象实现的接口 那个接口叫什么名字 获取到它 生成第二个参数
还有你要增强的目标方法是什么? 参数是什么? 这些它都可以获取到。
理解了这些你也就理解 了jdk动态代理了
然后加一个细节 那个Proxy.newProxyInstance的第一个参数
什么是类加载器?
类加载器(Class Loader)是Java虚拟机(JVM)的一部分,它使用双亲委派机制,用于将类的字节码加载到内存中并生成对应的类对象。
当创建代理实例时,需要注入类加载器参数的原因是因为代理类的字节码需要被加载到内存中,并由类加载器生成对应的类对象。代理类在运行时动态生成,它不是在编译时就存在的。
因此,为了加载代理类的字节码并生成代理实例,需要提供一个类加载器,使得代理类的字节码能够被正确地加载到内存中。通过将类加载器作为参数注入,可以确保代理类能够在正确的类加载器的命名空间下进行加载和使用。
通过上面的实践就不难理解了。 它通过上面这个过程 生成了最终的FOO的代理对象。