什么是动态代理?Spring中有哪几种实现?有什么区别?
答: 1. 可以任意的控制任意对象的执行过程,这个对象的执行过程可以由客户端灵活的指定
2. 两种
3. jdk和CGLib
JDK
1. JDK version <= 1.6 的时候实现InvocationHandler,重写invoke,自定义初始化对象(method.invoke(Object,args))
2.利用拦截器(必须要实现InvocationHandler接口)加上反射机制生成一个代理接口的匿名类,在具体方法前调用InvocationHandler来处理
CGlib
1.实现MethodInterceptor 重写intercept (methodProxy.invokeSuper(Object,args))
2.CGLib利用ASM框架,对代理对象生成的class文件加载进来,通过修改其字节码文件生成子类来处理
2.CGLib不能对声明final的类和方法进行代理,因为CGlib原理是动态生成被代理类的子类
3.完全不受代理类必须实现接口类的限制,采用的是接口继承的方式
接口(inteface)
public interface JdkHello {
public String hello();
public String world();
}
正常实现类(class)
/**
* @author youshang
*/
public class JdkHelloImpl implements JdkHello {
@Override
public String hello() {
return "hello";
}
@Override
public String world() {
return "world";
}
}
代理实现类(Proxy Class)
@Log4j2
public class JdkHelloProxy implements JdkHello {
private JdkHello jdkHello = new JdkHelloImpl();
@Override
public String hello() {
log.info("通过动态代理执行hello");
return jdkHello.hello();
}
@Override
public final String world() {
log.info("通过动态代理执行world");
return jdkHello.world();
}
}
代理类(Proxy)
/**
* JDK1.6+ 底层提供的动态代理
*/
@Log4j2
public class JdkProxy {
private Object object;
public JdkProxy(Object object){
this.object = object;
}
/**
* 封装代理方法,取代实现InvocationHandler
* @return
*/
public Object getProxyInstance() {
long startTime = System.currentTimeMillis();
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), (proxy, method, args) -> {
DateTime startDate = DateUtil.date(startTime);
log.info(String.format("开始操作你的需求: %s ",startDate));
//进行代理
Object invoke = method.invoke(object, args);
long endTime = System.currentTimeMillis();
log.info(String.format("操作此需求总共耗时: %s 毫秒",(endTime- startTime)));
return invoke;
});
}
// (proxy, method ,args) -> method.invoke(proxy,args)
// =
// new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// return method.invoke(object,args);
// }
}
代理类(Proxy)
/**
* JDK1.6+ 底层提供的动态代理
*/
@Log4j2
public class JdkProxy {
private Object object;
public JdkProxy(Object object){
this.object = object;
}
/**
* 封装代理方法,取代实现InvocationHandler
* @return
*/
public Object getProxyInstance() {
long startTime = System.currentTimeMillis();
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), (proxy, method, args) -> {
DateTime startDate = DateUtil.date(startTime);
log.info(String.format("开始操作你的需求: %s ",startDate));
//进行代理
Object invoke = method.invoke(object, args);
long endTime = System.currentTimeMillis();
log.info(String.format("操作此需求总共耗时: %s 毫秒",(endTime- startTime)));
return invoke;
});
}
// (proxy, method ,args) -> method.invoke(proxy,args)
// =
// new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// return method.invoke(object,args);
// }
}
测试代理类(Test)
/**
* 测试jdk动态代理
*/
public class JdkProxyTest {
@Test
public void test(){
//通过代理类实现调用JdkHelloImpl实现类
JdkHello jdkHello = new JdkHelloProxy();
//执行代理操作
JdkHello jdkHelloProxy = (JdkHello)new JdkProxy(jdkHello).getProxyInstance();
System.out.println(jdkHelloProxy.hello());
//经过final修饰的方法
System.out.println(jdkHelloProxy.world());
}
}
代理目标类(class)
public class CglibServiceImpl{
public String say() {
return "say";
}
public String useCase() {
return "useCase";
}
/**
* final修饰的方法,CGLib不能代理
* @return
*/
public final String example(){
return "劳资的东西你别碰。。。";
}
}
代理类(Proxy Class)
/**
* 实现CGLib核心接口 MethodInterceptor
*/
@Log4j2
public class CglibProxy implements MethodInterceptor {
private Long startTime;
public CglibProxy(){
startTime = System.currentTimeMillis();
}
/**
* 回调接口的方法
* 回调接口的方法执行的条件是:代理对象执行目标方法时会调用回调接口的方法
* @param obj
* @param method
* @param args
* @param proxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
log.info(String.format("方法名: %s",method.getName()));
log.info(String.format("开始执行日期: %s ", DateUtil.date(startTime)));
Object o = proxy.invokeSuper(obj, args);
long endTime = System.currentTimeMillis();
log.info(String.format("方法总共执行时间: %s 毫秒",endTime - startTime));
return o;
}
}
测试CGlib代理方法
@Test
public void test(){
Enhancer enhancer = new Enhancer();
//将目标类设置为父类,cglib动态代理增强的原理就是子类增强父类,cglib不能增强目标类为final的类和方法
enhancer.setSuperclass(CglibServiceImpl.class);
//设置当前类的具体子类(允许为null)
enhancer.setClassLoader(CglibServiceImpl.class.getClassLoader());
//设置回调接口,这里的MethodInterceptor实现类回调接口,而我们又实现了MethodInterceptor
enhancer.setCallback(new CglibProxy());
//create()方法用于创建cglib动态代理对象
CglibServiceImpl cglibService = (CglibServiceImpl)enhancer.create();
//实现CGLib代理调用方法
System.out.println(cglibService.say());
System.out.println(cglibService.useCase());
//通过final修饰的方法,CGlib没办法代理
System.out.println(cglibService.example());
}