在上一章使用了Enhancer,没有仔细说明代理的问题,在这一章进行详细的说明。
原本想使用cf包的,后来发现使用framework包下的包也没有问题,程序中就一直使用framework中的类。
一:概述
1.说明
CGLIB是一个强大、高性能的字节码生成库,它用于在运行时扩展Java类和实现接口;
本质上它是通过动态的生成一个子类去覆盖所要代理的类(非final修饰的类和方法)。
Enhancer是一个非常重要的类,它允许为非接口类型创建一个JAVA代理,Enhancer动态的创建给定类的子类并且拦截代理类的所有的方法,和JDK动态代理不一样的是不管是接口还是类它都能正常工作。
2.回调接口
net.sf.cglib.proxy.Callback接口:在cglib包中是一个很关键的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。
net.sf.cglib.proxy.MethodInterceptor接口: 是通用的回调(callback)类型,他经常被AOP用来实现拦截(intercept)方法的调用;
3.关于MethodInterceptor接口的源代码
是Callback的子接口,所以,实现这个接口的类可以用于回调。
package org.aopalliance.intercept; @FunctionalInterface public interface MethodInterceptor extends Interceptor { Object invoke(MethodInvocation var1) throws Throwable; }
二:示例
1.结构
2.对象
package com.jun.web.enhancer; public class HelloWorld { public String say(boolean say) throws Exception { System.out.println("Hello Student"); if(!say) { throw new Exception("回答错误!"); } return "回答正确!"; } }
3.回调
package com.jun.web.enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class HelloWorldInterceptor implements MethodInterceptor { /** * * 方法描述 当对基于代理的方法回调时,在调用原方法之前会调用该方法 * 拦截对目标方法的调用 * * @param obj 代理对象 * @param method 拦截的方法 * @param args 拦截的方法的参数 * @param proxy 代理 * @return * @throws Throwable */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { Object result = null; try { //前置通知 before(); result = proxy.invokeSuper(obj, args); //后置通知 after(); } catch (Exception e) { //异常通知 exception(); } finally { //方法返回前通知 beforeReturning(); } return result; } private void before() { System.out.println("before method invoke..."); } private void after() { System.out.println("after method invoke..."); } private void exception() { System.out.println("exception method invoke..."); } private void beforeReturning() { System.out.println("beforeReturning method invoke..."); } }
4.代理
package com.jun.web.enhancer; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; //创建Enhancer增强代理类的回调ProxyFactory类 public class ProxyFactory { //要代理的真实对象 private Object obj; public Object createProxy(Object target) { Enhancer enhancer = new Enhancer(); //设置代理目标 enhancer.setSuperclass(target.getClass()); //设置单一回调对象,在调用中拦截对目标方法的调用 enhancer.setCallback(new HelloWorldInterceptor()); //设置类加载器 enhancer.setClassLoader(target.getClass().getClassLoader()); return enhancer.create(); } }
5.测试
package com.jun.web.enhancer; public class EnhancerTest { public static void main(String[] args) throws Exception { //将要被代理的对象 HelloWorld hello = new HelloWorld(); //代理 ProxyFactory proxy = new ProxyFactory(); // HelloWorld world = (HelloWorld)proxy.createProxy(hello); String result = world.say(false); System.out.println(result); } }
6.效果
Connected to the target VM, address: '127.0.0.1:60279', transport: 'socket' before method invoke... Hello Student exception method invoke... beforeReturning method invoke... null Disconnected from the target VM, address: '127.0.0.1:60279', transport: 'socket'
三:其他回调
1.FixedValue
net.sf.cglib.proxy.FixedValue:为提高性能,FixedValue回调对强制某一特定方法返回固定值。
package com.jun.web.enhancer; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.FixedValue; public class FixedValueTest { public static void main(String[] args) throws Exception { HelloWorld hello = new HelloWorld(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(hello.getClass()); //设置单一回调对象,在调用中拦截对目标方法的调用 enhancer.setCallback(new FixedValue() { @Override public Object loadObject() throws Exception { return "FixedValue"; } }); //设置类加载器 enhancer.setClassLoader(hello.getClass().getClassLoader()); HelloWorld world = (HelloWorld)enhancer.create(); String result = world.say(false); System.out.println(result); } }
2.效果
Connected to the target VM, address: '127.0.0.1:60379', transport: 'socket' Disconnected from the target VM, address: '127.0.0.1:60379', transport: 'socket' FixedValue Process finished with exit code 0
3.NoOp
net.sf.cglib.proxy.NoOp:NoOp回调把对方法调用直接委派到这个方法在父类中的实现(也可以理解成真实对象直接调用方法);
package com.jun.web.enhancer; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.NoOp; public class NoopTest { public static void main(String[] args) throws Exception { HelloWorld hello = new HelloWorld(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(hello.getClass()); enhancer.setCallback(NoOp.INSTANCE); enhancer.setClassLoader(hello.getClass().getClassLoader()); HelloWorld obj = (HelloWorld)enhancer.create(); System.out.println(obj.say(true)); } }
4.效果
Disconnected from the target VM, address: '127.0.0.1:60418', transport: 'socket' Hello Student 回答正确! Process finished with exit code 0
5.其他的回调
net.sf.cglib.proxy.LazyLoader:当实际的对象需要延迟装载时,可以使用LazyLoader回调。一旦实际对象被装载,它将被每一个调用代理对象的方法使用;
net.sf.cglib.proxy.Dispatcher:Dispathcer回调和LazyLoader回调有相同的特点,不同的是,当代理方法被调用时,装载对象的方法也总要被调用;
net.sf.cglib.proxy.ProxyRefDispatcher:ProxyRefDispatcher回调和Dispatcher一样,不同的是,它可以把代理对象作为装载对象方法的一个参数传递;
四:CallbackFilter回调
1.说明
net.sf.cglib.proxy.CallbackFilter允许我们在方法层设置回调(callback),根据我们对方法处理的需求设置不同的回调;如下有一个类Hello,里面有两个方法save和update,save方法需要做前置和后置处理,但是update方法不需要:
2.Hello
package com.jun.web.enhancer; public class Hello { public String save() { System.out.println("save..."); return "save"; } public String update() { System.out.println("update..."); return "update"; } }
3.
package com.jun.web.enhancer; import org.springframework.cglib.proxy.CallbackFilter; import java.lang.reflect.Method; public class CallBackFilterTest implements CallbackFilter { /** * 方法返回的值是和callback回调接口数组一一对应的数组下标 */ @Override public int accept(Method method) { String name = method.getName(); if("save".equals(name)) { return 0; } return 1; } }
4.测试
package com.jun.web.enhancer; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.NoOp; public class CallbackFilterMainTest { public static void main(String[] args) throws Exception { Hello hello = new Hello(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(hello.getClass()); enhancer.setCallbackFilter(new CallBackFilterTest()); //创建各个目标代理方法的回调,回调的顺序要与过滤器索引一致 Callback[] callbacks = new Callback[] {new HelloWorldInterceptor(), NoOp.INSTANCE}; //设置单一回调对象,在调用中拦截对目标方法的调用 enhancer.setCallbacks(callbacks); Hello obj = (Hello)enhancer.create(); System.out.println(obj.update()); System.out.println("============="); System.out.println(obj.save()); } }
5.效果
Connected to the target VM, address: '127.0.0.1:60873', transport: 'socket' update... update ============= before method invoke... Disconnected from the target VM, address: '127.0.0.1:60873', transport: 'socket' save... after method invoke... beforeReturning method invoke... save Process finished with exit code 0