动态代理
动态代理类似于设计模式中的代理模式,在Java中的体现就是,给目标类生成一个代理类,用代理类来调用目标类的具体方法,并可以在调用前后给目标方法执行一些附加功能,最简单的应用就是Spring中的Aop,使用@Transactional
注解可以在不写事务相关代码的情况下给方法增加事务
动态代理的实现方式
有两种实现方式,
- JDK动态代理,即Java语言提供的动态代理实现
- CGLIB动态代理,第三方库实现的动态代理
JDK动态代理
JDK动态代理的实现需要目标类必须实现了某个接口,然后才能够给目标类添加增强方法
Talk is cheap, Show me the code
// 一个接口
public interface HelloService {
void sayHi();
}
// 一个实现类
public class HelloServiceImpl implements HelloService {
@Override
public void sayHi() {
System.out.println("你好,我是HelloService的实现类");
}
}
// 一个动态代理类
public class HelloProxy implements InvocationHandler {
/**
* 目标类的实例
*/
private Object target;
public HelloProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是代理,实现增强开始...");
final Object result = method.invoke(target, args);
System.out.println("我是代理,实现增强结束...");
return result;
}
}
// 一个测试类
public class JdkDynamicProxyDemo {
public static void main(String[] args) throws Exception {
// 创建代理类并执行代理方法的第一种方法
// 1.生成$Proxy0.class文件
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 2.获取动态代理类
final Class<?> proxyClass = Proxy.getProxyClass(HelloService.class.getClassLoader(), HelloService.class);
// 3.获取代理类的构造器并传入InvocationHandler.class
final Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);
// 4.通过构造器生成代理对象
final HelloService proxyObject = (HelloService) constructor.newInstance(new HelloProxy(new HelloServiceImpl()));
// 5.调用目标方法
proxyObject.sayHi();
// 创建代理类并执行代理方法的第二种方法
// 直接使用proxy类的静态方法newProxyInstance,整合了第一种方法的五个步骤
final HelloService proxyObject2 = (HelloService) Proxy.newProxyInstance(
HelloService.class.getClassLoader(),
new Class[]{HelloService.class},
new HelloProxy(new HelloServiceImpl())
);
}
}
输出如下:
>>> 我是代理,实现增强开始...
>>> 你好,我是HelloService的实现类
>>> 我是代理,实现增强结束...
想要使用JDK动态代理的目标类,必须要实现一个接口,否则就不能被成功代理
CgLib实现动态代理
CgLib实现动态代理与JDK动态代理不同的是,CgLib不要求被代理类实现接口,CgLib的实现原理是,对目标类生成一个代理类继承于目标类,然后调用代理类的超类的方法,在方法调用前后进行方法增强操作
因为是第三方库,我们需要添加以下依赖或者直接引入spring-framework
的依赖也可以
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
// 一个目标类
public class TargetClass {
final public void sayHello() {
System.out.println("大家好,我是final的sayHello");
}
public void sayHi() {
System.out.println("大家好,我是自由的sayHi");
}
}
// 一个代理类
public class ProxyClass implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("这是cglib动态代理增强, 开始");
// 调用父类的方法
final Object result = methodProxy.invokeSuper(o, objects);
System.out.println("这是cglib动态代理增强, 结束");
return result;
}
}
// 一个测试类
public class CgLibProxyDemo {
public static void main(String[] args) {
// 生成代理对象$Proxy0.class
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "Your/Target/Path");
// 创建Enhancer对象,类似于JDK动态代理的Proxy类
Enhancer enhancer = new Enhancer();
// 设置目标类
enhancer.setSuperclass(TargetClass.class);
// 设置回调
enhancer.setCallback(new ProxyClass());
// 创建代理类
final TargetClass targetClass = (TargetClass) enhancer.create();
// 调用代理方法
targetClass.sayHi();
}
}