“ 在前一篇文章我们了解了Spring AOP的简单运用,我们发现面向切面编程的核心是动态代理,我们这篇文章主要就是看一下:JDK自带的动态代理和CGLIB的动态代理”
注:JDK实现动态代理方式需要被代理的类拥有接口,CGLIB方式要求被代理类没有被final修饰
相关文章:Spring AOP的简单应用
Class类文件结构
01
—
JDK动态代理技术
首先定义一个接口
代码语言:javascript复制interface SuperObject {
void execute();
}
被代理类:
代码语言:javascript复制class RealObject implements SuperObject {
@Override
public void execute() {
System.out.println("执行方法");
}
}
声明一个代理类需要我们实现reflect包下面的一个接口InvocationHandler。其中invoke方法我们大概看一下proxy就是被代理的类了,其中Method也是reflect包下的类,代表了类的方法。
代码语言:javascript复制public class JdkProxy implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
代理类对被代理类进行方法的增强:
代码语言:javascript复制public class JdkProxy implements InvocationHandler {
private Object target;
public JdkProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置方法");
Object o = method.invoke(target, args);
System.out.println("后置方法");
return o;
}
}
测试:Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回某个对象的代理对象。其中第一个参数是类加载器,第二个参数是代理类实现的接口,这也是我们说为什么要代理类要实现接口才行。第三个参数是调用处理器,调用实现了InvocationHandler 类的一个回调方法
代码语言:javascript复制 public static void main(String[] args) {
SuperObject superObject = (SuperObject)
Proxy.newProxyInstance(RealObject.class.getClassLoader(),
RealObject.class.getInterfaces(),
new JdkProxy(new RealObject()));
superObject.execute();
}
结果:
代码语言:javascript复制Connected to the target VM, address: '127.0.0.1:50982', transport: 'socket'
前置方法
执行方法
后置方法
Disconnected from the target VM, address: '127.0.0.1:50982', transport: 'socket'
02
—
CGLib动态代理技术
使用CGLIB实现动态代理需要我们引入Jar包,这里我导入相应的依赖文件
代码语言:javascript复制<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
定义被代理的类,这个类实现MethodInterceptor,可以理解为方法拦截器,并且实现其方法intercept。
代码语言:javascript复制public class ProxySubject implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//用于创建无参的目标对象代理类,对于有参构造器则调用Enhancer.create(Class[] argumentTypes, Object[] arguments),第一个参数表示参数类型,第二个参数表示参数的值。
return enhancer.create();
}
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("前置方法");
Object result = methodProxy.invokeSuper(object, args);
System.out.println("后置方法");
return result;
}
}
测试:
代码语言:javascript复制public class Main {
public static void main(String[] args) {
RealSubject subject = (RealSubject) new ProxySubject().getProxy(RealSubject.class);
subject.sayHello();
}
}
结果:
代码语言:javascript复制Connected to the target VM, address: '127.0.0.1:50982', transport: 'socket'
前置方法
hello
后置方法
Disconnected from the target VM, address: '127.0.0.1:50982', transport: 'socket'
到这里就介绍了JDK与CGLib两种动态代理技术,最近自己空闲时间也在研究关于Spring AOP的实现源码,发现了不少新的东西:比如ASM和拦截链,ASM框架是一个致力于字节码操作和分析的框架,它可以用来修改一个已存在的类或者动态产生一个新的类,换句话说他可以修改class文件,前面我们有一篇文章聊到了class文件说明,在一些博客上我看到有人说一些高手可以直接修改class文件,来修改方法,大家可以私下研究研究。