动态代理
绪论
一、什么是动态代理
是使用反射和字节码的技术,在运行期创建指定接口或类的子类,以及其实例对象的技术,通过这个技术可以无侵入的为代码进行增强(代码无侵入的增强)
举例:卖车,工厂把车生产出来,经销商4s店买车,工厂就是被代理的类,4s就是代理类,4s店对车进行送膜,送脚垫,送保养就是做增强。
二、jdk动态代理
1、jdk实现动态代理主要是俩个类,Proxy、InvocationHandler,
- Proxy: 是所有动态代理的父类,它提供了一个静态方法来创建动态代理的class对象和实例
- InvocationHandler: 每个动态代理实例都有一个关联的
InvocationHandler
,在代理实例上调用方法是,方法调用将被转发到InvocationHandler
的invoke方法
代码层:
2、代理类实现InvocationHandler接口
public class DynamicHandler implements InvocationHandler { private Object target; public DynamicHandler(Object target) { this.target=target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前 System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args)); //被增强的方法执行 Object res = method.invoke(target, args); //方法之后 System.out.println("方法之后执行...."+target); return res; } }
3、服务层
public interface DynamicService { Integer add(Integer a, Integer b); Integer sub(Integer a, Integer b); } public class DynamicServiceImpl implements DynamicService { @Override public Integer add(Integer a, Integer b) { int c=a+b; System.out.println("答案:"+c); return c; } @Override public Integer sub(Integer a, Integer b) { int c=a-b; System.out.println("答案:"+c); return c; } }
4、实现jdk代理
Proxy.newProxyInstance代理类:
public void testFun1(){ Class[] classes={DynamicService.class}; //代理类 DynamicService proxyInstance =(DynamicService) Proxy.newProxyInstance(this.getClass().getClassLoader(), classes, new DynamicHandler(new DynamicServiceImpl())); Integer result = proxyInstance.add(1, 2); System.out.println("result:"+result); }
JDK方法之前执行....add :JDK传递的参数...[1, 2]
答案:3
JDK方法之后执行....com.mvc.testdemo2.dynamic.DynamicServiceImpl@7cbd213e
result:3
三、cglib动态代理
1、CGLIB的实现也有两个重要的成员组成,Enhancer
、MethodInterceptor
- Enhancer 来指定要代理的目标对象,实际处理代理逻辑的对象,最终通过调用
create()
方法得到代理对象、对这个对象所有的非final方法的调用都会转发给MethodInterceptor
- MethodInterceptor 动态代理对象的方法调用都会转发到
intercept
方法进行增强
2、创建MethodInterceptor实现类
public class CGLIBDynamicHander implements MethodInterceptor { private Object target; public CGLIBDynamicHander(Object target) { this.target=target; } @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable { //方法之前 System.out.println("CGLIB方法之前执行...."+method.getName()+" :CGLIB传递的参数..."+ Arrays.toString(args)); //被增强的方法执行 Object res = method.invoke(target, args); //方法之后 System.out.println("CGLIB方法之后执行...."+target); return res; } }
3、实现cglib代理
@Test public void testFun2(){ Enhancer enhancer=new Enhancer(); DynamicServiceImpl dynamicService = new DynamicServiceImpl(); enhancer.setSuperclass(dynamicService.getClass()); enhancer.setCallback(new CGLIBDynamicHander(dynamicService)); DynamicServiceImpl dynamicServiceProxt =(DynamicServiceImpl) enhancer.create(); Integer result = dynamicServiceProxt.add(1, 2); System.out.println("result:"+result); }
CGLIB方法之前执行....add :CGLIB传递的参数...[1, 2]
答案:3
CGLIB方法之后执行....com.mvc.testdemo2.dynamic.DynamicServiceImpl@174d20a
result:3
四、总结
1、JDK原声动态代理时java原声支持的、不需要任何外部依赖、但是它只能基于接口进行代理(因为它已经继承了proxy了,java不支持多继承)
2、CGLIB通过继承的方式进行代理、无论目标对象没有没实现接口都可以代理,但是无法处理final的情况(final修饰的方法不能被覆写)
学有所思,思有所成。