jdk动态代理 和 CGLIB动态代理 详解

来源:互联网 发布:人工智能三驾马车 编辑:程序博客网 时间:2024/06/10 03:53

1. 静态代理模式

//目标接口public interface IDoSomething {public void doSomething();}
//目标对象public class DoSomething implements IDoSomething{public void doSomething() {System.out.println(" do something ");}}


如果使用继承的方式,可以直接继承后,覆盖父类方法,然后在此方法内部与调用父类的方法,实现代理此种形式无需父类实现接口
public class SubDoSomething extends DoSomething{@Overridepublic void doSomething() {System.out.println(" before ");super.doSomething();System.out.println(" end ");}public static void main(String[] args) {DoSomething t = new SubDoSomething();t.doSomething();}}

如果使用接口的形式,那么代理类必须跟被代理类实现同一个接口,代理类拥有被代理的对象在代理类实现接口方法时,直接调用被代理的对象来实现

public class StaticProxyDoSomething implements IDoSomething{IDoSomething t;public StaticProxyDoSomething(IDoSomething t) {this.t = t;}@Overridepublic void doSomething() {System.out.println(" before ");t.doSomething();System.out.println(" end ");}public static void main(String[] args) {IDoSomething t1 = new DoSomething();IDoSomething t2 = new StaticProxyDoSomething(t1);t2.doSomething();}}

静态代理模式,必须针对单个指定的类进行代理,如果有多个类需要代理的话,需要写太多重复的代理类

而且如果被代理类增加一个方法,对应的代理类都必须进行修改


2. JDK动态代理,可以直接使用反射的方式,动态调用被代理类的方法,具体步骤:

1.写一个通用代理类,实现java.lang.reflect.InvocationHandler接口,实现invoke()方法

2.代理类需要通过反射,来调用被代理的对象,那么首先需要获取被代理的对象,一般可以通过构造函数传入

   然后需要构造一个被代理的对象(Proxy.newProxyInstance()),最后在invoke方法里面调用相应方法

   实际上,JDK直接生成了一个代理类的class文件类似:$DoSomethingProxy.class,这个class实现了IDoSomething接口并继承了Proxy
   (因为要继承Proxy,所以不能直接继承DoSomething,那么就必须要实现一个接口了,这就是JDK动态代理必须有接口的原因)

package com.ourselvesoft.catering.test.other.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class MyInvocationHandler implements InvocationHandler{//获取目标对象public Object target;public MyInvocationHandler(Object target) {this.target = target;}//使用反射调用对应的方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(" before ");Object result = method.invoke(target, args);System.out.println(" end ");return result;}//获取代理对象public Object getProxy() {return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}public static void main(String[] args) {IDoSomething t = new DoSomething();MyInvocationHandler handler = new MyInvocationHandler(t);//IDoSomething proxy = (IDoSomething)Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), handler);IDoSomething proxy = (IDoSomething)handler.getProxy();proxy.doSomething();}}

3. cglib动态代理

    cglib动态代理则无需被代理类实现任何接口(但是cglib采用了动态创建子类的方法,因而无法代理final方法)

    首先实现net.sf.cglib.proxy.MethodInterceptor 接口,实现其intercept方法(getProxy传入被代理class)

public class CGLibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();public Object getProxy(Class clazz) {// 设置需要创建子类的类enhancer.setSuperclass(clazz);enhancer.setCallback(this);// 通过字节码技术动态创建子类实例return enhancer.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(" before ");// 通过代理类调用父类中的方法Object result = proxy.invokeSuper(obj, args);System.out.println(" after ");return result;}public static  void main(String[] args) {CGLibProxy proxy = new CGLibProxy();DoSomething t = (DoSomething)proxy.getProxy(DoSomething.class);t.doSomething();}}


spring aop 默认使用JDK 动态代理,在没有接口的情况下,会使用cglib动态代理

0 0
原创粉丝点击