6、动态代理
谈及动态代理,难免避不开Java的反射技术。
Java的反射机制:
在程序运行时通过加载已知的class,从而可以操作类或者属性和方法。Java是先编译再运行的语言,Java源文件都是要先经过编译生成class文件,当程序需要动态加载某些类时,它就可以通过反射机制来创建对象并调用方法。
Java 反射api的使用方法在这里不做赘述,不懂的同学可以移驾这里→反射api的使用
说完反射机制,我们来说说动态代理在常用框架Spring中支持模式:JDK Proxy 或者 cglib,不过先来看下动态代理给我们带来了什么?
动态代理:
它是一种代理机制,从静态代理发展到动态代理,代理模式我们可以看成是对调用目标的一种包装,不用直接调用目标方法,通过调用调用代理类的代理方法,来达到对调用目标方法的增强,也可以说这是类似装饰器模式的应用,同时也实现调用者和调用目标之间的解耦。
应用场景:
动态代理是Spring AOP的基础实现,通过动态代理我们可以实现在不同时期调用同一个方法达到不同的目的。例如在日志、事务、用户鉴权、全局异常处理等。
JDK Proxy:
public class PersonHandler implements InvocationHandler {
private PersonDao personDao;
public PersonHandler(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("先进行热身运动");
Object invoke = method.invoke(personDao, args);
System.out.println("结束进行放松运动");
return invoke;
}
}
测试:
@Test
void test5(){
Person person = new Person();
PersonHandler personHandler = new PersonHandler(person);
PersonDao personProxy= (PersonDao) Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
personHandler
);
personProxy.run();
}
实现对应的InvocationHandler接口,再通过PersonDao为纽带给目标对象建立一个代理对象,应用程序就可以利用这个代理对象间接调用目标对象的方法逻辑,我们再通过在invoke()方法内添加额外的方法,从而可以实现对目标对象方法的增强。
JDK Proxy 是接口为中心的, 相当于添加了一种对于被调用者没有太大意义的限制。如果被调用者没有实现相应的接口,是无法实现JDK Proxy的,这种情况下,我们可以转而使用cglib方式。
cglib:
被代理类:
public class UserService {
public void run(){
System.out.println("我还是在跑步!!!");
}
}
接口实现:
public class AutoMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("先热个身");
Object object = methodProxy.invokeSuper(obj, args);
return object;
}
}
测试:
@Test
void test6(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new AutoMethodInterceptor());
UserService userService = (UserService)enhancer.create();
userService.run();
}
cglib动态代理采取的方式是创建目标类的子类,通过子类可以很容易使用被调用类的方法。