AOP是面向切面,即扩展功能但是不修改源代码,AOP采取横向抽取机制,一般用于 性能监控、事务管理、安全检查、缓存;
这里先介绍一下纵向抽取机制:
我们一般添加功能是这样做的:
public class User {
public void add() {
//添加用户的功能
//添加打印日志的功能
}
public void test() {
//添加用户的功能
//添加打印日志的功能
}
// ......
}
这样的缺点是每个需要添加打印日志功能的方法都需要在方法里面添加相关的代码,很不方便,于是便诞生了纵向抽取机制的解决方法;
public class BaseLog {
//添加日志功能
public void writeLog() {
//功能代码
}
}
public class User extends BaseLog{
public void add() {
//添加用户的功能
//添加打印日志的功能
super.writeLog();
}
public void test() {
//添加用户的功能
//添加打印日志的功能
super.writeLog();
}
// ......
}
因为这样的方式是通过继承这种纵向关系实现的,所以也叫纵向抽取机制,AOP采用的是不是这个而是横向抽取机制,横向抽取机制主要用的是动态代理,也就是AOP的核心,所以结合Spring(一),我们总结一下:
要实现动态代理,Java提供了两种方式,即JDK自己提供的动态代理和第三方的CGLIB,在有接口的情况下,我们使用的是JDK提供的动态代理: 这块可参考→动态代理
我们需要一个接口、该接口的具体实现类(目标类)、代理辅助类(需要实现InvocationHandler接口):
public class Proxy implements InvocationHandler {
public void invoke() {
//添加特有的前置功能
//目标类
method.invoke();
//添加特有的后置功能
}
}
在没有接口的情况下,使用CGlib的代理方式;
通知分5种:
Spring中的AOP实现还是比较简单的,AOP的实现借助于Aspectj框架(这是一个独立的框架,不是Spring的一部分!!),AOP的实现有两种方式,即配置和注解:
两种方式都需要用execution()的表达式来配置切入点:
execution(<访问修饰符><返回类型><方法名>(<参数>)<异常>)
1、execution(* com.tulun.bean.User.add(..)) //表示某个类下面的指定方法
2、execution(* com.tulun.bean.User.*(..)) //表示某个包下面某个类的所有方法
3、execution(* *.*(..)) //表示所有
AOP的实现需要在Spring基本的jar包上再添加如下的jar包:
org.springframework
spring-aop
4.1.7.RELEASE
org.aspectj
aspectjweaver
1.6.0
aopalliance
aopalliance
1.0
步骤:
一、引入依赖
就上面那个;
二、创建相关的类
这是一个需要被增强的类:
public class User {
//需要被增强的方法
public void add() {
System.out.println("User.add()");
}
}
这是一个提供增强功能的类:
public class Log {
public void writeLog() {
System.out.println("写日志功能");
}
}
三、创建xml文件aop1.xml配置相关:
四、使用
测试:
public class TestDemo1 {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("注解实现AOP/aop1.xml");
User user = (User) context.getBean("user");
user.add();
}
}
这是使用的前置通知,其他的通知也差不多,就环绕通知特殊一点,下面是一个环绕通知的实现:
需要在增强类里面添加一个环绕通知的方法:
public class Log {
//环绕通知
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("前置功能");
joinPoint.proceed();
System.out.println("后置功能");
}
}
修改一些xml配置文件(就修改了我打标记的那一行):
测试:
public class TestDemo2 {
@Test
public void testAround() {
ApplicationContext context = new ClassPathXmlApplicationContext("配置实现AOP/aop-Around.xml");
User user = (User) context.getBean("user");
user.add();
}
}
通过注解实现那就更简单了,步骤如下:
一、引入依赖
略;
二、创建相关的类
和上面一样的,
public class User {
//需要被增强的方法
public void add() {
System.out.println("User.add()");
}
}
public class Log {
public void writeLog() {
System.out.println("写日志功能");
}
}
三、创建XML文件,配置相关
四、添加注解
在增强类上面添加@Aspect,在增强方法上面添加相关通知:
@Aspect
public class Log {
@Before(value = "execution(* com.tulun4.User.add())")
public void writeLog() {
System.out.println("写日志功能");
}
}
前置通知:@Before
后置通知:@After
环绕通知:@Around
最终通知:@AfterReturning
异常通知:@AfterThrowing
以上注解都是作用于方法上,该方法为切入点,既要增加功能的方法,
@Before、@After、@Around的value的值是要使用execution的函数表达式;
execution表达式和配置中使用的方法和效果是一样的;
五、使用
测试:
public class TestDemo1 {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("注解实现AOP/aop1.xml");
User user = (User) context.getBean("user");
user.add();
}
}