首页 > 代码库 > jdk动态代理与cglib代理、spring aop代理实现原理解析

jdk动态代理与cglib代理、spring aop代理实现原理解析

原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主

代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

动态代理实现主要有2种形式,主要分为:
1.jdk动态代理:
1)原理:是根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口 面向接口生成代理,位于java.lang.reflect包下)
2)实现方式:
1. 通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
2~4步骤可合并

package proxy.jdkproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import org.junit.Test;public class JDKProxy{    //写法1    private Object targetObject;//代理目标    public Object CustomerProxy(Object obj) {        targetObject = obj;        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(),new targetHandler());    }    class targetHandler  implements InvocationHandler{        @Override        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {             System.out.println("开启事务...");               Object returnValue = http://www.mamicode.com/method.invoke(targetObject, args);//回调被代理目标的方法userDaoImpl.add();  "提交事务");               return returnValue;          }    }    public static void main(String[] args) {          JDKProxy jdkProxy = new JDKProxy();          Customer userDao = (Customer)jdkProxy.CustomerProxy(new CustomerImpl());          userDao.shopping();      }      //写法2    @Test    public void test1(){        Customer customer = new CustomerImpl();        Customer cus = (Customer) Proxy.newProxyInstance(customer.getClass().getClassLoader(), customer.getClass().getInterfaces(),new InvocationHandler(){            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                // TODO Auto-generated method stub                return method.invoke(proxy, args);            }        });        cus.shopping();    }}

3)不足点:jdk动态代理,必须是面向接口,目标业务类必须实现接口
2.CGLIB代理
1.原理:利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
2.实现方法:

package proxy.cglib;import java.lang.reflect.Method;import org.junit.Test;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import proxy.model.Customer;public class CGLIBProxy {    //写法1    private Object targetObject;    private Object createProxy(Object obj){        targetObject = obj;        Enhancer enhancer = new Enhancer();        enhancer.setSuperclass(targetObject.getClass());//设置代理对象,父类,说明是继承,所有代理对象不能为final        enhancer.setCallback(new MyHandler());        return enhancer.create();//创建代理    }    class MyHandler implements MethodInterceptor{        @Override        public Object intercept(Object arg0, Method method, Object[] args,                MethodProxy arg3) throws Throwable {            System.out.println("开启事务..");              Object returnValue = http://www.mamicode.com/method.invoke(targetObject, args);  "提交事务....");              return returnValue;          }    }    @Test    public  void test1() {          CGLIBProxy cglibProxy = new CGLIBProxy();          Customer customer = (Customer)cglibProxy.createProxy(new Customer());          customer.eat();      }      //写法2    @Test    public void test2(){        Customer customer = new Customer();        Enhancer enhancer = new Enhancer();        enhancer.setSuperclass(customer.getClass());        enhancer.setCallback(new MethodInterceptor() {            @Override            public Object intercept(Object proxy, Method method, Object[] args,                    MethodProxy arg3) throws Throwable {                if(method.getName().equals("eat")){                      System.out.println("customer的eat方法被拦截了。。。。");                      Object invoke = method.invoke(proxy, args);                      System.out.println("真实方法拦截之后。。。。");                      return invoke;                  }                  // 不拦截                  return method.invoke(proxy, args);              }        });        Customer cus = (Customer) enhancer.create();        cus.eat();    }}

3.注意点:被代理目标不是是final修饰的类(final修饰类不能被继承)
spring aop代理原理
1.注意点:

  • 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
  • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
  • 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

2.强制把jdk代理转换成cglib代理

  • 添加CGLIB库,SPRING_HOME/cglib/*.jar
  • 在spring配置文件中加入技术分享
    传统AOP可以实现自动代理,不需要专门指定代理,可以在类生成的时候自动代理,有两种方式实现自动代理,基于Bean名称的自动代理BeanNameAutoProxyCreator和基于切面信息的自动代理DefaultAdvisorAutoProxyCreator

spring mvc 使用DefaultAdvisorAutoProxyCreator实现自动代理 配置

<!--定义一个表示声明使用自动代理的类  -->    <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>    <!-- 定义代理类 -->    <bean id="exceptionHandler" class="com.kaizhi.platform.util.ExceptionHandler"/>    <!-- 定义支持正则表达式的通知 -->    <bean id="exceptionHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">                     <property name="advice">            <ref bean="exceptionHandler"/>        </property>        <property name="patterns">            <value>.save*.*</value>//正则匹配需要拦截的方法        </property>     </bean>

spring mvc 使用BeanNameAutoProxyCreator自动代理配

<!-- 基于BeanNameAutoProxyCreator,Bean名称的自动代理 -->      <!-- 定义代理类 -->    <bean id="exceptionHandler" class="com.kaizhi.platform.util.ExceptionHandler"/>    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">          <!-- 拦截的业务bean -->          <property name="beanNames" value="http://www.mamicode.com/*adminFinanceService"/>          <!-- 拦截的通知 -->          <property name="interceptorNames" value="http://www.mamicode.com/exceptionHandler"/>      </bean>

参考:http://blog.csdn.net/zx13525079024/article/details/51913141

jdk动态代理与cglib代理、spring aop代理实现原理解析