为了让博客内容看着舒服一些,所以我把静态代理和动态代理的代码在最后了哦!
1. 动态代理和静态代理
什么是代理?
- 为某⼀个对象创建⼀个代理对象,程序不直接用原本的对象,而是由创建的代理对象来控制对原对象,通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间。
- A ->B-> C (A类是调用方法的类,B类就是代理,C类是真正的方法)
静态代理:
由程序创建或特定工具自动生成源代码,在程序运行前,代理类的.class文件就已经存在。
动态代理:
在程序运行时,运用反射机制动态创建而成,无需手动编写代码。
- JDK动态代理
- CGLIB动态代理
2. 静态代理讲解
什么是静态代理?
- 由程序创建或特定工具自动生成源代码,在程序运行前,代理类的.class文件就已经存在
- 通过将目标类与代理类实现同⼀个接口,让代理类持有真实类对象,然后在代理类方法中调用真实类方法,再调用真实类方法的前后添加我们所需要的功能扩展代码来达到增强的目的
- A ->B-> C (A类是调用方法的类,B类就是代理,C类是真正的方法)
优点:
- 代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可
- 方便增加功能,拓展业务逻辑
缺点:
- 代理类中出现大量冗余的代码,非常不利于扩展和维护
- 如果接口增加⼀个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度
3. AOP的实现策略之JDK动态代理 和 CGLib动态代理
动态代理:
- 在程序运行时,运用反射机制动态创建而成,无需手动编写代码
- 动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器⼀个集中的方法中处理,解耦和易维护
- JDK动态代理与静态代理⼀样,目标类需要实现⼀个代理接口,再通过代理对象调用目标方法
- CGLib动态代理的原理是对指定的业务类生成⼀个子类,并覆盖其中的业务方法来实现代理
两种动态代理的区别:
- JDK动态代理是自带的,CGLib需要引入第三方包
- CGLib动态代理:它是在内存中构建⼀个子类对象从而实现对目标对象功能的扩展
- CGLib动态代理基于继承来实现代理,所以无法对final类、private方法和static方法实现代理
- JDK动态代理:要求目标对象实现⼀个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以用CGLib动态代理
Spring AOP中的代理使⽤的默认策略:
- 如果目标对象实现了接口,则默认采用JDK动态代理
- 如果目标对象没有实现接口,则采用CGLib进行动态代理
- 如果目标对象实现了接口,程序里面依旧可以指定使用CGLib动态代理
4. 静态代理及动态代理 之 实现案例
首先在项目中新建一个代理的包,包名为 proxy,
还记得文章开头的ABC吗?
A ->B-> C (A类是调用方法的类,B类就是代理,C类是真正的方法)
A:ProxyTest:调用方法的类
B:StaticProxyPayServiceImpl(静态代理)、JdkProxy(JDK动态代理)、CglibProxy(CGLib动态代理)
C:PayServiceImpl:真正的方法
PayService:该demo要实现的接口
结构如下:
该demo要实现的接口 – PayService:
public interface PayService {
String callback(String outTradeNo);
int save(int userId, int productId);
}
真正的方法 --PayServiceImpl:
public class PayServiceImpl implements PayService{
public String callback(String outTradeNo) {
System.out.println("PayServiceImpl 回调 方法 callback");
return outTradeNo;
}
public int save(int userId, int productId) {
System.out.println("PayServiceImpl 回调 方法 save");
return productId;
}
}
代理模块代码:
4.1 静态代理 – StaticProxyPayServiceImpl:
public class StaticProxyPayServiceImpl implements PayService{
private PayService payService;
//通过构造函数的方式注入
public StaticProxyPayServiceImpl(PayService payService){
this.payService = payService;
}
public String callback(String outTradeNo) {
System.out.println("StaticProxyPayServiceImpl callback begin");
String result = payService.callback(outTradeNo);
System.out.println("StaticProxyPayServiceImpl callback end");
return result;
}
public int save(int userId, int productId) {
System.out.println("StaticProxyPayServiceImpl save begin");
int id = payService.save(userId, productId);
System.out.println("StaticProxyPayServiceImpl save end");
return id;
}
}
4.2 JDK动态代理 – JdkProxy:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler {
//目标类
private Object targetObject;
//获取代理对象
public Object newProxyInstance(Object targetObject){
this.targetObject = targetObject;
//绑定关系,也就是和具体的哪个实现类关联
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
//Object proxy:被代理的对象
//Method method:要调⽤的⽅法
//Object[] args:⽅法调⽤时所需要参数
public Object invoke(Object proxy, Method method, Object[] args) {
Object result = null;
try {
System.out.println("通过JDK动态代理调用"+method.getName()+",打印日志 begin");
result = method.invoke(targetObject,args);
System.out.println("通过JDK动态代理调用"+method.getName()+",打印日志 end");
} catch (Exception e){
e.printStackTrace();
}
return result;
}
}
4.3 CGLib动态代理 – CglibProxy:
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
//目标类
private Object targetObject;
//绑定关系
public Object newProxyInstance(Object targetObject){
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();
//设置代理类的⽗类(⽬标类)
enhancer.setSuperclass(this.targetObject.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建⼦类(代理对象)
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object result = null;
try {
System.out.println("通过CGLIB动态代理调用"+method.getName()+",打印日志 begin");
result = methodProxy.invokeSuper(o,args);
System.out.println("通过CGLIB动态代理调用"+method.getName()+",打印日志 end");
} catch (Exception e){
e.printStackTrace();
}
return result;
}
}
4.4调用方法的类 – ProxyTest:
想测试哪个,就把哪个的代码打开,这里只打开了CGLib代理的测试!
public class ProxyTest {
public static void main(String[] args) {
//正常调用
// PayService payService = new PayServiceImpl();
// payService.callback("fdvwtr");
//使用代理调用
// PayService payService = new StaticProxyPayServiceImpl(new PayServiceImpl());
// payService.save(123, 654);
// payService.callback("fdvwtr");
//JDK动态代理
// JdkProxy jdkProxy = new JdkProxy();
// //获取代理类对象
// PayService payServiceProxy = (PayService) jdkProxy.newProxyInstance(new PayServiceImpl());
// //调用目标方法
// payServiceProxy.callback("151sfds");
// payServiceProxy.save(1212,5656);
//CGLiB动态代理
CglibProxy cglibProxy = new CglibProxy();
PayService payService = (PayService)cglibProxy.newProxyInstance(new PayServiceImpl());
payService.callback("dsfasfasd");
payService.save(555,666);
}
}