zoukankan      html  css  js  c++  java
  • 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 = 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:aspectj-autoproxy proxy-target-class = "true" />

    传统AOP有默认的实现代理机制,可不需要专门指定代理,如自定义代理对象,可在类生成的时候自动代理,自动代理的方式主要有2种,一种是基于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>
  • 相关阅读:
    winform利用itextsharp.dll实现图片文件转换PDF格式文件
    winform 实现选择文件和选择文件夹对话框
    ASP利用xhEditor编辑器实现图片上传的功能。
    winform c#中子窗体关闭刷新父窗体
    ASP.NET js控制treeview中的checkbox实现单选功能
    js如何获取asp.net服务器端控件的值(label,textbox,dropdownlist,radiobuttonlist等)
    ASP.NET C# 登陆窗体 限制用户名只输入字母 数字以及下划线
    GridView通过RowDataBound事件获取字段值、数据源列值
    Window.Open()方法详细的参数说明及技巧。
    获取GridView中RowCommand的当前索引行(转)
  • 原文地址:https://www.cnblogs.com/zhaixiajiao/p/6772789.html
Copyright © 2011-2022 走看看