Spring基于AspectJ的AOP开发
在 spring-aspects 模块中引入了 AspectJ 工程。Spring 2.0 以后,Spring 新增了对 AspectJ 的支持。在新版本的 Spring 框架中,建议使用 AspectJ 方式开发 AOP。
@AspectJ 可以通过注解声明切面。为了能够使用 @AspectJ 注解,必须要开启 Spring 的配置支持。@AspectJ 注解支持以 XML 的方式进行切面声明配置,如 <aop:aspectj-autoproxy/> 标签配置,也可以通过 Java 配置的方式进行切面声明配置。
@EnableAspectJAutoProxy 注解用于开启 AOP 代理自动配置。AspectJ 的重要注解如表 1 所示。
@Pointcut 切点注解是匹配一个执行表达式。表达式类型如表 2 所示。
@Pointcut 切点表达式可以组合使用
(1)定义一个类,在类中定义一些切点,代码如下://声明切面类
(1)定义一个 @User 注解,代码如下:
声明:《Java系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。
@AspectJ 可以通过注解声明切面。为了能够使用 @AspectJ 注解,必须要开启 Spring 的配置支持。@AspectJ 注解支持以 XML 的方式进行切面声明配置,如 <aop:aspectj-autoproxy/> 标签配置,也可以通过 Java 配置的方式进行切面声明配置。
@EnableAspectJAutoProxy 注解用于开启 AOP 代理自动配置。AspectJ 的重要注解如表 1 所示。
| 注 解 | 说 明 |
|---|---|
| @Aspect | 定义一个切面,如果要被Spring管理,还需要配合使用@Component |
| @Pointcut | 定义切点 |
| @Before | 前置增强 |
| @ AfterReturning | 后置增强,在方法返回后执行 |
| @ AfterThrowing | 后置增强,在抛出异常后执行 |
| @After | 后置增强 |
| @Around | 环绕增强 |
@Pointcut 切点注解是匹配一个执行表达式。表达式类型如表 2 所示。
| 表 达 式 | 说 明 |
|---|---|
| execution | 匹配一个执行方法的连接点,如@Pointcut("execution(public * *(..))") |
| within | 限定连接点属于某个确定类型的类,如@Pointcut("within(com.xyz.someapp.trading..*)") |
| this | 匹配的连接点所属的对象引用是某个特定类型的实例,如@Pointcut("this(com. xyz .service .AccountService)") |
| target | 匹配的连接点所属的目标对象必须是指定类型的实例,如@Pointcut("target(com. xyz .service .AccountService)") |
| args | 匹配指定方法的参数,如@Pointcut("args(java.io.Serializable)") |
| @target |
匹配指定的连接点,该连接点所属的目标对象的类有一个指定的注解,如 @Pointcut("@target(org. springframework, transaction, annotation. Transactional)") |
| @args | 连接点在运行时传过来的参数的类必须要有指定的注解,如@Pointcut("@args (com. xyz. security. Classified)") |
| @within | 匹配必须包括某个注解的类中的所有连接点,如@Pointcut("@within(org. springframework, transaction, annotatio n. Transactional)") |
| @annotation | 匹配有指定注解的连接点,如 @Pointcut("@annotation(org.springframework, transaction, annotation.Transactional)") |
@Pointcut 切点表达式可以组合使用
&&、|| 或 ! 三种运算符。示例代码如下:@Pointcut("com.xyz.myapp.SystemArchiteacture.dataAccessOperation()&& args(account,..)")
@Around 通过注解的方法可以传入 ProceedingJoinPoint 参数,ProceedingJoinPoint 类实例可以获取切点方法的相关参数及实例等。基于 XML 配置的 AOP
下面的例子是基于 XML 方式配置的切面。(1)定义一个类,在类中定义一些切点,代码如下://声明切面类
public class AspectTest {
//方法执行前操作
public void before() {
System.out.println("before");
}
//方法执行后操作
public void after() {
System.out.println("after");
}
//方法环绕操作
public void around() {
System.out.println("around");
}
}
(2)定义目标对象,代码如下:
//定义目标类
public class UserService {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//执行方法
public void getUser() {
System.out.println("id:"+this.id);
System.out.println("name:"+this.name);
}
}
(3)基于 XML 方式配置切面,代码如下:<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:aspectj-autoproxy/> <bean id="aspectTest" class="com.spring.boot.AspectTest"/> <bean id="userService" class="com.spring.boot.UserService"> <property name="id" value="1"/> <property name="name" value="zhangsan"/> </bean> <aop:config> <aop:pointcut expression="execution(public * com.spring.boot.UserService.getUser(..))" id="pointcut"/> <aop:aspect order="1" ref="aspectTest"> <aop:before method="before" pointcut-ref="pointcut"/> </aop:aspect> <aop:aspect order="2" ref="aspectTest"> <aop:after method="after" pointcut-ref="pointcut"/> </aop:aspect> <aop:aspect order="3" ref="aspectTest"> <aop:after method="around" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> </beans>测试程序,代码如下:public class SpringXmlTest {
public static void main(String[] args) {
//通过spring.xml获取Spring应用上下文
ApplicationContext context = new ClassPathXmlApplication
Context("spring.xml");
UserService userService = context.getBean("userService",
UserService.class);
userService.getUser(); //打印结果
}
}
在以上代码中,<aop:aspectj-autoproxy>标签开启了全局AspectJ,<aop:config>标签定义了Pointcut和Aspect。基于 @Aspect 注解的 AOP
基于 @Aspect 注解的切面编程完全可以通过注解的形式完成。(1)定义一个 @User 注解,代码如下:
//定义@User注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface User {
}
(2)定义切面类,代码如下
//定义切面
@Aspect
@Component
public class AspectTest {
//定义切点,表示使用了@User注解的方法将会被增强处理
@Pointcut("@annotation(com.spring.boot.User)")
public void pointCut() {}
//在切点方法之前执行
@Before("pointCut()")
public void before() {
System.out.println("before");
}
//处理真实的方法
@Around("pointCut()")
public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable {
System.out.println("around before");
proceedingJoinPoint.proceed();
System.out.println("around after");
}
//在切点方法之后执行
@After("pointCut()")
public void after() {
System.out.println("after");
}
}
(3)新建配置类,代码如下:
//配置类开启切面配置
@EnableAspectJAutoProxy
@Configuration
@ComponentScan("com.spring.boot")
public class SpringConfigTest {
@Bean
public UserService userService() {
return new UserService();
}
public static void main(String[] args) {
//通过配置类获取Spring应用上下文
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfigTest.class);
UserService userService = context.getBean(UserService.class);
userService.setId(1);
userService.setName("zhangsan");
userService.getUser(); //打印属性值
}
}
(4)在目标类中增加 @User 注解,代码如下:
@Service
public class UserService {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//添加了@User注解的方法
@User
public void getUser() {
System.out.println("id:"+this.id);
System.out.println("name:"+this.name);
}
}声明:《Java系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。