动态代理
//接口类 public interface PersonBehavior { void talk(); void jump(); }
//实现类(被代理类) public class DefaultPersonBehavior implements PersonBehavior { @Override public void talk() { System.out.println("We can talk"); } @Override public void jump() { System.out.println("We can jump"); } }
public class PersonBehaviorHandler implements InvocationHandler { private Object target; public PersonBehaviorHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("We can do anything before ..."); Object result = method.invoke(target, args); return result; } }
//super man proxy PersonBehavior superManBehavior = new DefaultSuperManBehavior(); //获取superManBehavior相关的handler PersonBehaviorHandler superManHandler = new PersonBehaviorHandler(superManBehavior); //获取代理对象 PersonBehavior superManProxy = (PersonBehavior) Proxy.newProxyInstance(PersonBehavior.class.getClassLoader(), new Class<?>[]{PersonBehavior.class}, superManHandler); superManProxy.jump();
打印结果:We can do anything before ...
We can super jump
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); //这边生成了代理类 /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); //获取了构造器 final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); //生成了代理对象 } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
实际使用动态代理的时候,jdk为我们的生成了一个叫$Proxy0(这个名字后面的0是编号,有多个代理类会一次递增)的代理类,这个类文件时放在内存中的,我们在创建代理对象时,就是通过反射获得这个类的构造方法,然后创建的代理实例。
我们可以对InvocationHandler看做一个中介类,中介类持有一个被代理对象,在invoke方法中调用了被代理对象的相应方法。通过聚合方式持有被代理对象的引用,把外部对invoke的调用最终都转为对被代理对象的调用。
代理类调用自己方法时,通过自身持有的中介类对象来调用中介类对象的invoke方法,从而达到代理执行被代理对象的方法。也就是说,动态代理通过中介类实现了具体的代理功能
总结
生成的代理类:$Proxy0 extends Proxy implements Person,我们看到代理类继承了Proxy类,所以也就决定了java动态代理只能对接口进行代理,Java的继承机制注定了这些动态代理类们无法实现对class的动态代理。
参考: https://www.cnblogs.com/gonjan-blog/p/6685611.html
CGLIB代理
- CGLIB 原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
- CGLIB 底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
- CGLIB缺点:对于final方法,无法进行代理
为什么使用CGlib
- CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。我们知道Java中有一个动态代理也是做这个事情的,那我们为什么不直接使用Java动态代理,而要使用CGLIB呢?答案是CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了。
注意点
- CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
例子
//被代理对象 public class TargetClass { public String sayHello() { System.out.println("Hello everybody."); return "Hello"; } public String sayGoodBye() { System.out.println("GoodBye everyone;"); return "GoodBye"; } }
//方法拦截器 public class TargetInterceptor implements MethodInterceptor { /** * @param targetObj 目标对象 * @param method 目标方法 * @param params 参数 * @param methodProxy CGlib方法代理对象 */ @Override public Object intercept(Object targetObj, Method method, Object[] params, MethodProxy methodProxy) throws Throwable { System.out.println("Before invoke"); Object result = methodProxy.invokeSuper(targetObj, params); System.out.println("After invoke"); return result; } }
public class CglibTest { public static void main(String[] args) { //Enhancer是一个字节码增强器,它可以方便的对你要增强的类进行扩展 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetClass.class); enhancer.setCallback(new TargetInterceptor()); TargetClass targetObjectCglibProxy = (TargetClass) enhancer.create(); targetObjectCglibProxy.sayHello(); } }
-
CGlib的 回调过滤器CallbackFilter 和 FixedValue
package com.trip.study.proxy.cglib; import org.springframework.cglib.proxy.CallbackFilter; import java.lang.reflect.Method; public class TargetMethodCallBackFilter implements CallbackFilter { @Override public int accept(Method method) { if ("sayHello".equalsIgnoreCase(method.getName())) { System.out.println("CallBackFilter:sayHello" + 0); return 1; } //一个方法不可以同时匹配两次,以第一个匹配的为准 if ("sayHello".equalsIgnoreCase(method.getName())) { System.out.println("CallBackFilter:sayHello2" + 0); return 2; } if ("sayGoodBye".equalsIgnoreCase(method.getName())) { System.out.println("CallBackFilter:sayGoodBye" + 1); return 0; } return 0; } }
package com.trip.study.proxy.cglib; import org.springframework.cglib.proxy.FixedValue; public class TargetResultFixed implements FixedValue { @Override public Object loadObject() throws Exception { System.out.println("lock result"); return "what's your name ?"; } }
package com.trip.study.proxy.cglib; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.CallbackFilter; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.NoOp; public class TestCallBackFilter { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetClass.class); CallbackFilter callbackFilter = new TargetMethodCallBackFilter(); //NoOp.INSTANCE:这个NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截 Callback noOp = NoOp.INSTANCE; //callback方法拦截器 Callback callback = new TargetInterceptor(); //我们还可以加入结果拦截器,无论结果返回什么,都会返回what's your name ? Callback callbackResult = new TargetResultFixed(); //noOp对应TargetMethodCallBackFilter中return 0(在数组中的下标),同理callback对应的是1,callbackResult对应的是2 Callback[] callbacks = {noOp, callback, callbackResult}; enhancer.setCallbackFilter(callbackFilter); enhancer.setCallbacks(callbacks); TargetClass proxy = (TargetClass) enhancer.create(); String result = proxy.sayHello(); System.out.println("Result ===== " + result); } }
- 有问题欢迎指出,共同学习
来源:oschina
链接:https://my.oschina.net/u/4055223/blog/3213062