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 ,添加日志修改参数,对消息进行装饰,以取代原有对象行为的执行

posted @ 2018-01-18 17:23  暖暖-木木  阅读(275)  评论(0编辑  收藏  举报