重温jdk动态代理和cglib代理的区别:
jdk动态代理
- 实现InvocationHandler接口,重写invoke方法,加上自己想要的逻辑代码。
- 创建代理目标对象
- 通过Proxy.newInstance(classLoader,interfaces,InvocationHandler子类);去创建代理类,之后强转或者使用泛型方法。
- 通过代理类来进行方法的调用。
要求:代理类和目标对象需要实现同一个接口!!!
可以看出,jdk动态代理依赖于其实现了接口,并且对接口进行“增强”。若类不实现一个接口时,则无法使用jdk动态代理。
cglib就是弥补了jdk动态代理的不足。
CGLib
- 实现MethodInterceptor接口,重写intercept方法对代理对象的方法进行拦截。
- 通过创建Enhance(增强)来设置超类,去通过enhance.create()创建代理对象的子类,对超类中的方法进行拦截,从而实现自己额外的业务逻辑(性能检测,权限控制,事务,日志等)。
原理:通过动态生成复杂的字节码,创建目标类的子类,进行代理实现。final修饰的类不能进行代理。
JDK动态代理通过反射调用目标对象,cglib采用类似索引的方式直接调用目标对象中的方法。
JAVA实现
JDKDynamic 代理:
package com.logan;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** JDK 动态代理:被代理的对象需要实现一个接口,代理类对被代理类的方法进行拦截,在实际执行被代理类的方法前后,加上日志,事务,权限控制等。。** 1.事务,日志,权限控制是和业务逻辑不相干的,它们是垂直正交的关系。则可看做AOP中的"切面"。* 2.切入的方法,比如在Dao层所有的add*,update*,delete*之前的方法加上事务,成功了就提交事务,失败了就回滚。* 可称之为切点 CutPoint*** JDK 动态代理 : spring 中默认使用JDK动态代理,若想使用CGLib,则需要配置 <aop:con?g proxy-target-class="true"> 默认为false* 随着JDK版本的不断升级,最开始jdk动态代理的效率逐渐在提高。** 优点:* 1.对比静态代理来说,动态代理可以代码复用。* 2.使用静态代理时,如果代理类和被代理类同时实现了一个接口,当接口方法有变动时,代理类也必须同时修改。** 缺点:* 1.只能代理实现了接口的类,否则将不能使用JDK 动态代理。*** @author logan** @Date 2019年04月20日15:12:42**/
public class JDKDynamicProxy implements InvocationHandler {private Object target;public JDKDynamicProxy(Object target){this.target = target;}public <T> T getProxy(){return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),this.target.getClass().getInterfaces(), this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("jdk dynamic proxy before .....");long startTime = System.currentTimeMillis();Object object = method.invoke(target, args);long endTime = System.currentTimeMillis();System.out.println("jdk dynamic proxy after .....");System.out.println("jdk dynamic proxy spend time is " + (endTime - startTime) );return object;}}
CGLib Demo :
package com.logan;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/**** CGLibProxy demo** 为了弥补JDK动态代理的不足,cglib代理在底层字节码的基础上创建类,因为需要动态的去创建类,所以创建类所花费的时间要大于JDK动态代理* 若一次创建,多次服务,那么效果还是比较好的。*** @author logan*/
public class CGLibProxy implements MethodInterceptor {private Object target;private Enhancer enhancer = new Enhancer();public CGLibProxy(Object target){this.target = target;}/*** get proxy object* @param <T>* @return*/public <T> T getProxy(){enhancer.setSuperclass(target.getClass());enhancer.setCallback(this);return (T) enhancer.create();}public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("proxy before .....");long startTime = System.currentTimeMillis();//Object object = methodProxy.invoke(target, args);Object object = methodProxy.invokeSupper(o, args);long endTime = System.currentTimeMillis();System.out.println("proxy after .....");System.out.println("spend time is " + (endTime - startTime) );return object;}
}
测试接口:
package com.logan;public interface IMaster {void sayHello(String name);String select(String name);}
测试实现类:
package com.logan;public class Master implements IMaster {public void sayHello(String name){System.out.println("Hello, " + name);}public String select(String name){return "name = " + name;}}
Tester类:
package com.logan;/*** 测试类*/
public class Tester {public static void main(String[] args) {IMaster master = new CGLibProxy(new Master()).getProxy();master.sayHello("Logan");System.out.println(master.select("Nancy"));System.out.println("=============");IMaster proxyMaster = new JDKDynamicProxy(new Master()).getProxy();proxyMaster.sayHello("xiaoma");System.out.println(proxyMaster.select("123"));}}