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笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。