原创声明:本博客来源与本人另一博客【http://blog.csdn.net/liaohaojian/article/details/63683317】原创作品,绝非他处摘取

代理(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 = method.invoke(targetObject, args);//回调被代理目标的方法userDaoImpl.add();
             System.out.println("提交事务");
             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 = method.invoke(targetObject, args);
            System.out.println("提交事务....");
            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="*adminFinanceService"/>
        <!-- 拦截的通知 -->
        <property name="interceptorNames" value="exceptionHandler"/>
    </bean>

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

jdk动态代理与cglib代理、spring aop代理实现原理的更多相关文章

  1. Spring AOP 的实现 原理

    反射实现 AOP 动态代理模式实例说明(Spring AOP 的实现 原理)   比如说,我们现在要开发的一个应用里面有很多的业务方法,但是,我们现在要对这个方法的执行做全面监控,或部分监控.也许我们 ...

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

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  3. 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  4. jdk动态代理与cglib代理、spring Aop代理原理-代理使用浅析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  5. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  6. Spring -- <tx:annotation-driven>注解基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)的区别。

    借鉴:http://jinnianshilongnian.iteye.com/blog/1508018 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional ...

  7. Spring <tx:annotation-driven>注解 JDK动态代理和CGLIB动态代理 区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  8. JDK动态代理和CGLIB代理的区别

    一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...

  9. java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总

    若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. ...

随机推荐

  1. Eclipse多个console的使用

    我们在使用Eclipse开发服务器端和客户端时,经常需要同时运行服务器端和客户端,以便联调运行情况.而我之前一般有两种做法: 使用Java的命令行模式运行,但这种做法通常比较麻烦,因为要使用大串的cl ...

  2. wemall app商城源码Android短信监听接收器

    wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...

  3. SQLSERVER2008 错误18456

    我遇到的问题,已经解决,如果你遇到不能解决可以咨询我 1.以windows验证模式进入数据库管理器. 第二步:右击sa,选择属性: 在常规选项卡中,重新填写密码和确认密码(改成个好记的).把强制实施密 ...

  4. 1640: [Usaco2007 Nov]Best Cow Line 队列变换

    1640: [Usaco2007 Nov]Best Cow Line 队列变换 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 543  Solved: 2 ...

  5. MySQL数据库设计总结

    规则1:一般情况可以选择MyISAM存储引擎,如果需要事务支持必须使用InnoDB存储引擎. 注意:MyISAM存储引擎 B-tree索引有一个很大的限制:参与一个索引的所有字段的长度之和不能超过10 ...

  6. python 机器学习 K-近邻算法

    本人想边写文章,边学习,用的是 网上最火的<机器学习实战>machine learning in action 来做一次实践. 希望在过程中理顺思路之余,也有分享自己的一些理解,学习.加油 ...

  7. 2017-3-18 SQL server 数据库 45道题

    use data02161212 create table student (Sno nvarchar(3) primary key, Sname nvarchar(8) not null, Ssex ...

  8. (6)简单说说java中的线程

    先甩出来两种创建线程的方法: private static int count = 100; public static void main(String[] args) { // 用继承Thread ...

  9. 使sublimetext3在ubuntu下可以打中文和在windows的dos命令行下正常显示中文

    学习闲暇之余,总结一下在windows和ubuntu下使用sublimetext3遇到的问题 一.关于sublimetext3在windows的dos命令行下不能编译运行中文的解决方案: 因为dos命 ...

  10. 说说JAVA之网络编程 - 爬虫

    首先总结一下学习过程中所需要的类: URL类 - openConnection() URLConnection类 - connection() getInputStream() BufferedRea ...