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动态代理可以这样做:
-
首先实现一个InvocationHandler,方法调用会被转发到该类的invoke()方法。
-
然后在需要使用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 ,添加日志修改参数,对消息进行装饰,以取代原有对象行为的执行