JDK 动态代理
使用反射机制在方法执行过程中动态地添加功能
Java 实现动态代理主要涉及以下几个类:
- java.lang.reflect.Proxy: 这是生成代理类的主类,通过 Proxy 类生成的代理类都继承了 Proxy 类,即 DynamicProxyClass extends Proxy。
- java.lang.reflect.InvocationHandler: 这里称他为"调用处理器",他是一个接口,我们动态生成的代理类需要完成的具体内容需要自己定义一个类,而这个类必须实现 InvocationHandler 接口。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
import org.junit.Test;
/** * JDK 动态代理 */ public class JdkProxyTest {
public Object getProxy(final Object target) {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } System.out.println("[before] The method");
// 调用目标方法 Object result = null; try { // 前置通知 result = method.invoke(target, args); // 返回通知, 可以访问到方法的返回值 } catch (NullPointerException e) { e.printStackTrace(); // 异常通知, 可以访问到方法出现的异常 } // 后置通知. 因为方法可以能会出异常, 所以访问不到方法的返回值 // 打印日志 System.out.println("[after] The method"); return result; } }); }
@Test public void test() { ITarget target = new Target();
JdkProxyTest proxy = new JdkProxyTest();
ITarget targetProxy = (ITarget) proxy.getProxy(target);
targetProxy.exec(); }
}
interface ITarget { void exec(); }
class Target implements ITarget { public void exec() { System.out.println("正在执行方法"); } } |
缺点:目标对象必须实现接口,不能针对类创建代理类
CGLib 动态代理
简述
Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用,它的运行速度要远远快于JDK的Proxy动态代理
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;
public class CglibTest {
public static Object ceateProxtObject(final Object object, Class clazz) { // 声明增加类实例 Enhancer en = new Enhancer(); // 设置被代理类字节码,CGLIB根据字节码生成被代理类的子类 en.setSuperclass(clazz); // 设置回调函数,即一个方法拦截 en.setCallback(new MethodInterceptor() {
/** * Object表示要进行增强的对象 * Method表示拦截的方法 * Object[]数组表示参数列表,基本数据类型需要传入其包装类型,如int-->Integer、long-Long、double-->Double * MethodProxy表示对方法的代理,invokeSuper方法表示对被代理对象方法的调用 */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("[before] The method");
// 注意参数object,仍然为外部声明的源对象,且Method为JDK的Method反射 // Object o = method.invoke(object, args); Object o = proxy.invokeSuper(obj, args);
System.out.println("[after] The method"); return o; } }); return en.create(); }
public static void main(String[] args) { // // 未实现接口的类的代理 // Person proxyPerson = (Person) CglibTest.ceateProxtObject(new Person(), Person.class); // proxyPerson.exec();
// 实现接口的类的代理 ITarget proxyTarget = (ITarget) CglibTest.ceateProxtObject(new Target(), Target.class); proxyTarget.exec(); } } |