zoukankan      html  css  js  c++  java
  • Spring动态代理

     Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。

    代理作用:实现无侵入式的代码扩展,在invoke,intercept 中增加其他逻辑

    JDK代理:只能对实现了接口的类(如 helloserviceimpl )的类生成代理。

    Cglib代理:针对类实现代理,对指定的类生成一个子类,覆盖其中的方法,继承的关系。

    默认的策略是如果目标类是接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理。

    如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。

    java动态代理Cglib 代理和 JDK代理

    JDK 代理实现:

    public interface HelloService {
    void sayHello(String name);
    }
    public class HelloServiceImpl implements HelloService {
        @Override
        public void sayHello(String name) {
         System.out.println("hello"+name);
            
        }
    }

    用Java JDK动态代理可以这样做: 

    1. 首先实现一个InvocationHandler,方法调用会被转发到该类的invoke()方法。

    2. 然后在需要使用HelloService 的时候,通过JDK动态代理获取HelloService 的代理对象。

    public class ProxyFactory {
        public static  <T> T getProxyService(Class<T> tClass) {
    
            //动态获取目标类(通过socket将要调用的对象(类,方法,参数)传输到目标机器上面,目标机器通过反射执行完方法之后将结果返回)
            //第一个参数 代理类加载器
            return (T) Proxy.newProxyInstance(ProxyFactory.class.getClassLoader(),
                    //第二个参数 目标类
                    new Class<?>[]{tClass}
                    //第三个参数 代理目标类 中具体执行的动作(方法)
                    , new ProxyHandler()
            );
    
        }
    }
    
    public class ProxyHandler implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) {
    
            RPCTransformObj rpcTransformObj = new RPCTransformObj();
            String fullClassName = method.getDeclaringClass().getAnnotation(ServiceMapp.class).name();
            rpcTransformObj.setFullClassName(fullClassName);
            rpcTransformObj.setMethodName(method.getName());
            rpcTransformObj.setArgs(args);
            //通过socket 传输要调用的目标类,方法,参数
            return RPCInvocationHandler.callRemoteService(rpcTransformObj, "localhost", 7929);
        }
    }
     //动态获取目标对象
     UserService userService = ProxyFactory.getProxyService(UserService.class);
    // 1. 首先实现一个InvocationHandler,方法调用会被转发到该类的invoke()方法。
    public
    class JDKProxy2 implements InvocationHandler { private HelloService hello; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("hello before"); Object result = method.invoke(hello, args); // Object result = method.invoke(target, args); System.out.println("hello after"); return result; } public JDKProxy2(HelloService hello) { this.hello = hello; } // 2. 然后在需要使用Hello的时候,通过JDK动态代理获取Hello的代理对象。 public static void main(String[] args) {
    HelloService hello = (HelloService) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), // 1.类加载器
    new Class<?>[] { HelloService.class }, // 2. 代理需要实现的接口,可以有多个
    new JDKProxy2(new HelloServiceImpl()));// 3. 方法调用的实际处理者
    hello.sayHello("fyp");
    //newProxyInstance()会返回一个实现了指定接口的代理对象,对该对象的所有方法调用都会转发给InvocationHandler.invoke()方法
    //对代理对象的所有接口方法调用都会转发到InvocationHandler.invoke()方法,在invoke()方法里我们可以加入任何逻辑,记录日志,修改参数等;

    }
    }

    Proxy.newProxyInstance三个参数:

      1.loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

       2.interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它, 那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

       3.一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

    #HelloService 代理对象的类型信息

    class=class jdkproxy.$Proxy0

    superClass=class java.lang.reflect.Proxy

    interfaces: 

    interface jdkproxy.HelloService 

    invocationHandler=jdkproxy.JDKProxy2@a09ee92

    Cglib 代理实现

    是实现不是接口的类的动态代理

    public class Hello {
        public String sayHello(String str) {
            return "Hello: " + str;
        }
    }

    通过cglib代理实现的

    
    
    public class CglibProxy implements MethodInterceptor{
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
              return proxy.invokeSuper(obj, args);
        }
    
        public static void main(String[] args) {
            Enhancer  eh=new Enhancer();
            //指定代理对象 
            eh.setSuperclass(Hello.class);
            eh.setCallback(new CglibProxy());
            //调用create()方法得到代理对象
            Hello hello = (Hello)eh.create();
            System.out.println(hello.sayHello("I love you!"));
        }
    }
    
    

    我们通过CGLIB的Enhancer来指定要代理的目标对象、实际处理代理逻辑的对象,最终通过调用create()方法得到代理对象,对这个对象所有非final方法的调用都会转发给MethodInterceptor.intercept()方法

    cglib代理是通过继承类实现的

    
    

    # Hello代理对象的类型信息

    class=class cglib.Hello$$EnhancerByCGLIB$$e3734e52

    superClass=class lh.Hello

    interfaces: 

    interface net.sf.cglib.proxy.Factory

    invocationHandler=not java proxy class

    作用:一般用于aop ,添加日志修改参数,对消息进行装饰,以取代原有对象行为的执行

  • 相关阅读:
    UVA 11384 Help is needed for Dexter(问题转化 递归)
    UVA 11991 Easy Problem from Rujia Liu?(vector map)
    poj 2656 Unhappy Jinjin
    解析磁盘0号扇区数据
    树的非递归遍历
    iOS项目开发实战——使用同步请求获取网页源码
    单点登录cas常见问题(四)
    bzoj2115【WC2001】Xor
    最小化JavaScript代码
    quick-cocos2d-x教程9:实例之加上背景图片
  • 原文地址:https://www.cnblogs.com/fanBlog/p/8311019.html
Copyright © 2011-2022 走看看