您现在的位置是:首页 >技术教程 >SpringAOP 原理分析网站首页技术教程
SpringAOP 原理分析
#Spring AOP
Spring AOP 的核心思想是面向切面,面向切面这个思想对于编程经验少的人很难理解,下面通过分析Spring AOP的原理来深刻的体会。
- 静态代理
- JDK动态代理
- CGLIB动态代理
一 静态代理
假设我们有一个数据服务DataService,这个服务两个方法:add(), del()
现在有一个类DataServiceImplA实现了这个服务,并且有一个代理类通过实现类DataServiceImplA来代理这个服务。
那么我们可以写代码:
//数据服务
interface DataService{
void add();
void del();
}
//实现类
class DataServiceImplA implements DataService{
@Override
public void add(){
System.out.println("add");
}
@Override
public void del(){
System.out.println("del");
}
}
//代理类
class DataServiceProxy implements DataService{
DataServiceImplA server = new DataServiceImplA();
@Override
public void add(){
server.add();
//自定义的内容
System.out.println("代理执行add方法,添加到日志")
}
@Override
public void del(){
server.del();
//自定义的内容
System.out.println("代理执行del方法,添加到日志")
}
}
//程序入口
public class StaticProxy{
public static void main(String[] args){
DataService service = new DataServiceProxy();
service.add();
service.del();
}
}
上面的代理方式就是静态代理,这种方式有什么问题呢?它的拓展性很差!
如果有个类DataServiceImplB也实现了数据服务DataService, 需要为其创建一个新的代理类来重写DataServiceImplB中的方法
二 JDK动态代理
使用上面那个例子, 利用Java中的反射,来实现动态代理。
数据服务类和实现类不再重复。
class ProxyInvocationHandler implements InvocationHandler {
private DataService service;
public ProxyInvocationHandler(DataService service) {
this.service = service;
}
public Object getDataServiceProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), service.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理类方法调用之前,进行自定义操作");
Object res = method.invoke(service,args);
System.out.println("代理类方法调用之后,进行自定义操作");
return res;
}
}
public class DynamicProxy {
public static void main(String[] args) {
//创建服务类
DataService serviceA = new new_DataServiceImplA();
//将实现了接口的服务类serviceA传入到代理Handler中,然后拿到服务类的代理
DataService serviceProxy = (DataService) new ProxyInvocationHandler(serviceA).getDataServiceProxy();
//代理类执行服务类的方法
serviceProxy.add();
serviceProxy.del();
}
}
可以看到这里有一个代理调用处理器类,这个类中有一个私有的数据服务属性, 构造方法将外部传入的方法赋给私有的方法。
getDataServiceProxy()方法创建代理对象。
当调用代理对象的方法时,会自动调用invoke()方法,可以在invoke()方法中添加处理逻辑,实现方法的调用,拦截和增强。
在这个代码中,很多都写死了,比如代理调用处理器类中的私有属性DataService,这里可以用Object来代替,
以上的代码可以改为:
class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public ProxyInvocationHandler(Object service) {
this.target = service;
}
public Object getTargeterviceProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), service.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理类方法调用之前,进行自定义操作");
Object res = method.invoke(service,args);
System.out.println("代理类方法调用之后,进行自定义操作");
return res;
}
}
public class DynamicProxy {
public static void main(String[] args) {
//创建服务类
DataService serviceA = new new_DataServiceImplA();
//将实现了接口的服务类serviceA传入到代理Handler中,然后拿到服务类的代理
DateService serviceProxy = (DateService) new ProxyInvocationHandler(serviceA).getTargetServiceProxy();
//代理类执行服务类的方法
serviceProxy.add();
serviceProxy.del();
}
}
三 CGLIB动态代理
JDK动态代理有什么缺点吗?
JDK动态代理要求代理的对象类必须实现接口。这一点是一个限制。
在这里使用一个新例子,假设当前我们有个拥有发送短信方法的类。
CGLIB动态代理如何代理这个类呢?
//具有短信功能的类
class SmsService{
public String sendSms(String phoneNumber, String message){
System.out.println("send message: "+message+"to "+phoneNumber);
return message;
}
}
/**
* 定义一个方法拦截器用来实现动态代理
**/
class DebugMethodsInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("在调用方法之前,执行自定义操作");
Object object = methodProxy.invoke(o, args);
System.out.println("在调用方法之后,执行自定义操作");
return object;
}
}
class CglibProxyFactory{
public static Object getServiceProxy(Class<?> clazz){
//创建动态代理增强类
Enhancer enhancer = new Enhancer();
//设置加载器
enhancer.setClassLoader(clazz.getClassLoader());
//设置被代理类
enhancer.setSuperclass(clazz);
//设置方法拦截器
enhancer.setCallback(new DebugMethodsInterceptor());
return enhancer.create();
}
}
public class CGLIBProxy {
public static void main(String[] args) {
SmsService smsService = (SmsService) CglibProxyFactory.getServiceProxy(SmsService.class);
smsService.sendSms("123456789", "Hello World");
}
}
首先有个方法拦截器类,这个拦截器用来拦截发送短信的方法,在方法调用前后进行一系列处理,例如日志,鉴权等。
接下来是代理工厂类,代理工厂类有创建代理的方法,传入参数是被代理的目标类的class。Enhancer类是创建代理对象的核心类。setClassLoader方法用来设置代理类的类加载器,使用目标类的类加载器。 setSuperclass方法设置被代理的类,CGLIB通过继承目标类来代理对象。 setCallback方法设置拦截器,当代理对象调用目标方法的时候,触发拦截方法。
反思
Spring AOP 的核心目标是在不修改目标对象代码的前提下,对目标对象的方法进行增强,例如增加日志,鉴权,事务管理等。为了实现这个目标,Spring AOP通过在运行时创建代理对象来拦截目标对象的方法调用,并在方法调用前后插入额外逻辑。





QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
U8W/U8W-Mini使用与常见问题解决
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结