动态代理--jdk和cglib
一、含义
1、静态代理:简单,代理模式,是动态代理的理论基础。常见使用在代理模式
2、jdk动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用业务方法前调用InvocationHandler处理。代理类必须实现InvocationHandler接口,并且,JDK动态代理只能代理实现了接口的类,没有实现接口的类是不能实现JDK动态代理
3、cglib动态代理:可以直接代理类,使用字节码技术,不能对 final类进行继承。使用了动态生成字节码技术。
二、区别对比
JDK与Cglib动态代理对比?
1、JDK动态代理只能代理实现了接口的类,没有实现接口的类不能实现JDK的动态代理;
2、Cglib动态代理是针对类实现代理的,运行时动态生成被代理类的子类拦截父类方法调用,因此不能代理声明为final类型的类和方法;
动态代理和静态代理的区别?
1、静态代理在代理前就知道要代理的是哪个对象,而动态代理是运行时才知道;
2、静态代理一般只能代理一个类,而动态代理能代理实现了接口的多个类;
Spring如何选择两种代理模式的?
1、如果目标对象实现了接口,则默认采用JDK动态代理;
2、如果目标对象没有实现接口,则使用Cglib代理;
3、如果目标对象实现了接口,但强制使用了Cglib,则使用Cglib进行代理
三、.代码实现步骤
1、 jdk动态代理
步骤:
1.1、编写需要被代理的类和接口(我这里就是OrderServiceImpl、OrderService);
1.2、编写代理类(例如我这里的DynamicLogProxy),需要实现InvocationHandler接口,重写invoke方法;
1.3、使用Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)动态创建代理类对象,通过代理类对象调用业务方法。
2.cglib动态代理
cglib是针对类来实现代理的,它会对目标类产生一个代理子类,通过方法拦截技术对过滤父类的方法调用。代理子类需要实现MethodInterceptor接口
四、代码具体实现
public interface UserService { void saveUser(); }
public class UserServiceImpl implements UserService { @Override public void saveUser() { System.out.println("IoC 演示 之UserService" ); } }
package com.kkb.spring.utils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import com.kkb.spring.service.UserService; import com.kkb.spring.service.UserServiceImpl; /** * 主要作用就是生成代理类 * * @author think * */ public class MyProxyUtils { /** * 使用JDK的动态代理实现 它是基于接口实现的 * * @param serviceImpl * @return */ public static UserService getProxy(UserService service) { // Proxy是JDK中的API类 // 第一个参数:目标对象的类加载器 // 第二个参数:目标对象的接口 // 第二个参数:代理对象的执行处理器 UserService userService = (UserService) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("记录日志-开始"); // 下面的代码,是反射中的API用法 // 该行代码,实际调用的是目标对象的方法 Object object = method.invoke(service, args); System.out.println("记录日志-结束"); return object; } }); return userService; } /** * 使用CGLib动态代理技术实现 它是基于继承的方式实现的 * * @param service * @return */ public static UserService getProxyByCgLib(UserService service) { // 创建增强器 Enhancer enhancer = new Enhancer(); // 设置需要增强的类的类对象 enhancer.setSuperclass(UserServiceImpl.class); // 设置回调函数 enhancer.setCallback(new MethodInterceptor() { // MethodProxy:代理之后的对象的方法引用 @Override public Object intercept(Object object, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable { long start = System.currentTimeMillis(); System.out.println("记录程序开始时间..." + start); // 因为代理对象是目标对象的子类 // 该行代码,实际调用的是目标对象的方法 // object :代理对象 Object object2 = methodProxy.invokeSuper(object, arg); long end = System.currentTimeMillis(); System.out.println("记录程序结束时间..." + end); System.out.println("记录程序执行总时长..." + (end - start)); return object2; } }); // 获取增强之后的代理对象 UserService userService = (UserService) enhancer.create(); return userService; } }
package com.kkb.spring.test; import org.junit.Test; import com.kkb.spring.service.UserService; import com.kkb.spring.service.UserServiceImpl; import com.kkb.spring.utils.MyProxyUtils; public class TestProxy { @Test public void testJDKProxy() { //创建目标对象 UserService service = new UserServiceImpl(); //生成代理对象 UserService proxy = MyProxyUtils.getProxy(service); //调用目标对象的方法 service.saveUser(); System.out.println("==============="); //调用代理对象的方法 proxy.saveUser(); } @Test public void testCgLibProxy() { //创建目标对象 UserService service = new UserServiceImpl(); //生成代理对象 UserService proxy = MyProxyUtils.getProxyByCgLib(service); //调用目标对象的方法 service.saveUser(); System.out.println("==============="); //调用代理对象的方法 proxy.saveUser(); } }