前言
在学习spring的过程中,肯定避免不了要学习动态代理。我们先从代理模式开始介绍。
代理模式
- 代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问。
- 主要作用:是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
- 代理模式的思想:是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
静态代理
直接持有目标对象,并调用目标对象的方法。
- 缺点:每次都需要新建一个目标对象,使得代码非常繁琐
public class Target {
public void doSomething() {
System.out.println("target is doing something");
}
}
public class ProxyObject {
private Target target;
public ProxyObject(Target target) {
this.target = target;
}
public void proxyDoSomeThing() {
System.out.println("proxy target start.");
target.doSomething();
System.out.println("proxy target end.");
}
}
public class Test {
public static void main(String[] args) {
Target target = new Target();
// 某些场景不能直接用Target
ProxyObject proxy = new ProxyObject(target);
proxy.proxyDoSomeThing();
}
}
动态代理
动态代理,不需要每次都为代理对象新建一个代理类,只需要一个proxy即可。
动态代理目前有两种实现方式:JDK动态代理和CGLIB(Code Generation Library)动态代理。
两者的区别:
- JDK动态代理,委托对象必须实现了接口,没有实现接口的类,不能被代理
- cglib解决了JDK动态代理的问题,是针对类的代理。实现逻辑是通过继承实现代理,所以如果是final的对象,是不能用cglib动态代理。
(一)JDK动态代理,用匿名内部类实现
匿名内部类实现方式,可以少写几个代理类
/**
* 委托方/委托对象
*/
public interface Target {
public void doSomething();
}
public class TargetImpl implements Target{
public void doSomething() {
System.out.println("target is doing something");
}
}
// JDK动态代理:匿名内部类实现
public static Object jdkDynamicProxy(final Object object) {
// 三个参数:
// 1 ClassLoader loader, 可以用委托对象的classloader
// 2 Class<?>[] interfaces,动态代理类需要实现的类
// 3 InvocationHandler接口实现类,可以用匿名内部类实现。
// 其中invoke方法的三个参数:1 代理生成的实际代理类、2 代理的方法、3 方法的传入的参数。invoke方法返回一个Object对象,表示代理的方法调用之后返回的对象。
Target proxyTarget = (Target) Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
// 增强逻辑
System.out.println("动态代理:start打日志");
result = method.invoke(object, args);
// 增强逻辑
System.out.println("动态代理:end打日志");
return result;
}
});
return proxyTarget;
}
// 测试
public static void main(String[] args) {
System.out.println("动态代理:");
Target target = new TargetImpl();
Target jdkDynamicProxy = (Target)jdkDynamicProxy(target);
jdkDynamicProxy.doSomething();
}
(二)jdk动态代理,用代理类实现
此方式需要用代理类来绑定委托对象,比较麻烦,但是可以定制化修改方法。
// 动态代理类,实现了InvocationHandler 接口,并绑定了委托对象
public class JdkProxyObject implements InvocationHandler {
private Object target;
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = null;
// 增强
System.out.println("绑定方法:动态代理增强。start");
invoke = method.invoke(target, args);
// 增强
System.out.println("绑定方法:动态代理增强。end");
return invoke;
}
}
// 测试
public static void main(String[] args) {
Target target = new TargetImpl();
// jdk动态代理2:代理类绑定方式
JdkProxyObject jdkProxyObject = new JdkProxyObject();
Target jdkBindTarget = (Target)jdkProxyObject.bind(target);
jdkBindTarget.doSomething();
}
(三)cglib动态代理
引入maven依赖:
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
Enhancer类的create方法有多种重载方法,我们采用实现MethodInterceptor接口方式:
// 匿名内部类:MethodInterceptor接口,
public static Object cglibProxy(final Object object) {
return Enhancer.create(object.getClass(), new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object result = null;
// 增强逻辑
System.out.println("cglib动态代理:start打日志");
result = method.invoke(object, args);
// 增强逻辑
System.out.println("cglib动态代理:end打日志");
return result;
}
});
}
// 测试
public static void main(String[] args) {
Target target = new TargetImpl();
// cglib动态代理:
Target proxy = (Target) cglibProxy(target);
proxy.doSomething();
}
详细可以参阅:www.cnblogs.com/carpenterle…