在Java编程中,动态代理是一种在运行时动态创建代理类及其对象的技术。通过动态代理,我们可以在不修改原有类代码的情况下,为这些类添加新的行为或功能。Java提供了两种主要的动态代理机制:基于接口的Java动态代理和基于类的Cglib动态代理。在Spring AOP(面向切面编程)中,Cglib动态代理扮演着重要角色。本文将详细讨论这两种动态代理的实现。
一、Java动态代理
Java动态代理主要依赖于java.lang.reflect包中的Proxy类和InvocationHandler接口。它要求被代理的对象必须实现一个或多个接口,因为动态代理生成的代理类也是这些接口的实现类。
1.InvocationHandler接口
InvocationHandler接口定义了一个invoke方法,该方法在代理实例上的方法被调用时被调用。
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
其中,proxy是代理实例,method是被调用的方法,args是方法的参数。
2.代理实例
使用Proxy.newProxyInstance方法可以创建动态代理实例:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
其中,loader是类加载器,interfaces是代理类要实现的接口列表,h是调用处理器。
3.示例
假设我们有一个接口HelloService和一个实现类HelloServiceImpl:
public interface HelloService { void sayHello();
} public class HelloServiceImpl implements HelloService { @Override public void sayHello() { System.out.println("Hello, world!"); }
}
现在,我们想要为HelloService添加日志功能,但不修改HelloServiceImpl的代码。我们可以创建一个动态代理:
public class LogInvocationHandler implements InvocationHandler { private Object target; public LogInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = method.invoke(target, args); System.out.println("After method: " + method.getName()); return result; }
} public class DynamicProxyDemo { public static void main(String[] args) { HelloService helloService = new HelloServiceImpl(); LogInvocationHandler handler = new LogInvocationHandler(helloService); HelloService proxy = (HelloService) Proxy.newProxyInstance( helloService.getClass().getClassLoader(), helloService.getClass().getInterfaces(), handler ); proxy.sayHello(); // 调用代理实例的方法 }
}
在这个例子中,LogInvocationHandler实现了InvocationHandler接口,并在invoke方法中添加了日志功能。当我们调用proxy.sayHello()时,实际上是调用了LogInvocationHandler的invoke方法,从而实现了对原有方法的增强。
二、Cglib动态代理
Cglib是一个强大的高性能的代码生成库,它可以在运行时扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的拦截。
Cglib动态代理通过继承被代理类来创建代理对象,因此它不需要被代理类实现任何接口。这使得Cglib动态代理比Java动态代理更加灵活,因为Java中的类不一定需要实现接口
1.创建代理实例
使用Cglib创建代理实例通常涉及Enhancer类:
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass); // 设置要代理的目标类
enhancer.setCallback(callback); // 设置回调,用于处理代理方法调用
Object proxy = enhancer.create(); // 创建代理对象
其中,targetClass是要被代理的类,callback是实现了MethodInterceptor接口的回调对象,用于拦截和增强方法调用。
2.示例
假设我们有一个没有实现接口的类HelloServiceWithoutInterface:
public class HelloServiceWithoutInterface { public void sayHello() { System.out.println("Hello, world(无接口)!");}
}
现在,我们想要为这个类添加日志功能,可以使用Cglib动态代理来实现:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method; public class CglibLogInterceptor implements MethodInterceptor { private Object target; public CglibLogInterceptor(Object target) { this.target = target; } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before method (Cglib): " + method.getName()); Object result = proxy.invokeSuper(obj, args); // 使用proxy.invokeSuper来调用父类(即目标类)的方法 System.out.println("After method (Cglib): " + method.getName()); return result; }
} public class CglibDynamicProxyDemo { public static void main(String[] args) { HelloServiceWithoutInterface helloService = new HelloServiceWithoutInterface(); CglibLogInterceptor interceptor = new CglibLogInterceptor(helloService); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloServiceWithoutInterface.class); enhancer.setCallback(interceptor); HelloServiceWithoutInterface proxy = (HelloServiceWithoutInterface) enhancer.create(); proxy.sayHello(); // 调用代理实例的方法 }
}
在这个例子中,我们创建了一个CglibLogInterceptor类,它实现了MethodInterceptor接口,并在intercept方法中添加了日志功能。然后,我们使用Cglib的Enhancer类来创建HelloServiceWithoutInterface类的代理对象。当我们调用proxy.sayHello()时,实际上是调用了CglibLogInterceptor的intercept方法,从而实现了对原有方法的增强。
三、Spring AOP中的Cglib动态代理
在Spring AOP中,Cglib动态代理被广泛应用于那些没有实现接口的类。Spring AOP通过配置切面(Aspect)、连接点(Joinpoint)、通知(Advice)等概念,实现了对目标方法的拦截和增强。当目标对象没有实现接口时,Spring AOP会自动使用Cglib来创建代理对象。这使得Spring AOP能够灵活地处理各种情况,无论是基于接口的代理还是基于类的代理。
总结:
Java动态代理和Cglib动态代理都是强大的技术,它们允许我们在运行时动态地创建代理对象,并为这些对象添加新的行为或功能。Java动态代理基于接口,而Cglib动态代理基于类,这使得它们各自适用于不同的场景。在Spring AOP中,这两种动态代理技术都得到了广泛应用,为面向切面编程提供了强大的支持。通过理解和掌握这些技术,我们可以更加灵活地设计和实现复杂的Java应用程序。