什么是Spring AOP
Spring AOP 是Spring的核心功能,因为Java是面向对象编程,更多的是一个纵向的,但是遇到存在不存在关联和继承关系的横向关系时,就无法处理。所以这时可以通过切入点,将不相关的逻辑织入到当前业务代码中。
Spring AOP的类型
AOP的代理可分为
- 静态代理:编译时增强,使用AOP框架提供的命令进行编译,从而在编译阶段生成AOP代理类。
- 动态代理:运行时增强,借助JDK动态代理、CGLIB在内存中临时生成AOP动态代理类。
Spring 使用了同AspectJ 5 一样的注解,但是并没有 使用AspectJ编译器和织入器(Weaver),底层依然使用的Spring AOP 来实现动态代理生成AOP。
使用Spring AOP 实现AOP
- 启用注解模式
- 定义需要处理的Bean
// 使用 @Aspect 定义一个方面类
@Component
public class Chinese
{
public String sayHello(String name){
System.out.println("-- 正在执行 sayHello 方法 --");
// 返回简单的字符串
return name + " Hello , Spring AOP";
}
// 定义一个 eat() 方法
public void eat(String food){
System.out.println("我正在吃 :"+ food);
}
}
- 切入增加方法:事务控制、日志记录
//定义一个切面
@Aspect
public class AfterReturnTest{
//匹配包下所有的方法执行为切入点
@AfterReturning(return="rvt",pointcut="execution(* cn.com.bluemoon.service.impl.*.*")
public void log(Object rvt){
System.out.println("获取目标方法返回值:"+ rvt);
System.out.println("模拟日制记录...");
}
}
在程序中增加System.out.println(p.getClass());
代码可以输入p变量所引用对象的实现类,再次执行将看到代码产生class org...**.Chinese$EnhancerByCgLib$$290441d2的输出,这才是p变量所引用的对象的实现类,同时也是Spring AOP动态生成的AOP代理类。
若将上面程序稍作修改:让业务罗积累Chinese类实现一个任意接口例如:
public interface Person
{
String sayHello(String name);
void eat(String food);
}
接下来Beantest类面向Person接口、而不是Chinese类编程。
public class BeanTest
{
public static void main(String[] args)
{
// 创建 Spring 容器
ApplicationContext ctx = new
ClassPathXmlApplicationContext("bean.xml");
Person p = ctx.getBean("chinese" ,Person.class);
System.out.println(p.sayHello("张三"));
p.eat("西瓜");
System.out.println(p.getClass());
}
}
执行输出的将会是class$Proxy7,说明AOP代理由JDK动态代理生成。
Spring AOP 动态代理原则
类型 | 实现方式 |
---|---|
CGLIB | 目标对象实现类没有实现接口 |
JDK | 目标对象实现了接口 |
Spring AOP 原理
如图所示: Spring AOP的代理是由Spring的Ioc容易负责生成、管理,其依赖关系也由Ioc容器负责管理。因此,AOP代理可以直接使用容器中的其他bean实例座位目标,这种关系可由IOC容器的依赖注入提供。
而我们需要做的是:
- 定义普通业务组件
- 定义切入点,一个切入点可能横切多个业务组件
- 定义增强处理(After、Before、Around),AOP框架为普通业务组件织入(weaver)处理动作。
CGLIB 生成代理类
CGLIB(Code Generation Library)即代码生成库。可以在运行时动态的生成某个类的自雷。
AroundAdivice.java : 拦截器实现类
public class AroundAdvice implements MethodInterceptor
{
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)throws
java.lang.Throwable {
System.out.println("执行目标方法之前,模拟开始事务 ...");
// 执行目标方法,并保存目标方法执行后的返回值
Object rvt = proxy.invokeSuper(target, new String[]{"被改变的参数"});
System.out.println("执行目标方法之后,模拟结束事务 ...");
return rvt + " 新增的内容";
}
}
它的作可以在调用目标方法之前、调用目标方法之后织入增强处理。
ChineseProxyFactory.java:工作类
public class ChineseProxyFactory
{
public static Chinese getAuthInstance(){
Enhancer en = new Enhancer();
// 设置要代理的目标类
en.setSuperclass(Chinese.class);
// 设置要代理的拦截器
en.setCallback(new AroundAdvice());
// 生成代理类的实例
return (Chinese)en.create();
}
}
通过Enhancer 将Chinese类作为目标,以AroundAdvice对象作为ADvice,程序将会生成一个Chinese的子类,这个子类就是CGLIB生成的代理类,作为Chinese对象使用,但它增强了Chinese类的方法。
测试效果:
public class Main
{
public static void main(String[] args)
{
Chinese chin = ChineseProxyFactory.getAuthInstance();
System.out.println(chin.sayHello("孙悟空"));
chin.eat("西瓜");
System.out.println(chin.getClass());
}
}
-- 正在执行 sayHello 方法 --
执行目标方法之后,模拟结束事务 ...
被改变的参数 Hello , CGLIB 新增的内容
执行目标方法之前,模拟开始事务 ...
我正在吃 : 被改变的参数
执行目标方法之后,模拟结束事务 ...
class lee.Chinese$$EnhancerByCGLIB$$4bd097d9
小结
AOP广泛应用于处理一些具有横切性质的系统级服务,AOP的出现是对OOP的补充,它是的开发者能用更优雅的方式处理具有横切性质的服务。