背景:记录aop的使用方式。aop相关术语概念自行了解清楚,以下仅贴示例。
spring 版本:5.0.8.RELEASE
相关jar包,参考一下附件pom.xml
注意:各advice的执行顺序参考
https://blog.csdn.net/LGHunter/article/details/85330500
DAO
bean
package com.spring.aop.dao.bean;
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
dao
package com.spring.aop.dao.dao;
import com.spring.aop.dao.bean.User;
public interface UserDao {
void add(User user);
}
daoimpl
package com.spring.aop.dao.impl;
import com.spring.aop.dao.bean.User;
import com.spring.aop.dao.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
public void add(User user) {
System.out.println("添加用户,姓名:" + user.getName() + ",年龄:" + user.getAge());
}
}
Service
package com.spring.aop.service;
import com.spring.aop.dao.bean.User;
import com.spring.aop.dao.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void addUser(User user) {
userDao.add(user);
}
}
controller
package com.spring.aop.controller;
import com.spring.aop.dao.bean.User;
import com.spring.aop.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
@Autowired
private UserService userService;
public void addUser(User user) {
userService.addUser(user);
}
}
设置切点pointcut
package com.spring.aop.advice;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class PointCut {
//设置切点
//可以是接口,实现该接口的所有调用该实现方法的时候
@Pointcut("execution(public * com.spring.aop.dao.UserDao.add(..))")
// //可以是某具体实现类(或实现类某具体方法)
// @Pointcut("execution(public * com.spring.aop.dao.impl.UserDaoImpl.*(..))")
public void test(){}
}
两个切面aspect
package com.spring.aop.advice;
import com.spring.aop.dao.bean.User;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 切面的工作 - 通知
*/
@Component
@Aspect
public class TestAdvice1 {
@Before(value = "com.spring.aop.advice.PointCut.test()")
public void before(){
System.out.println("...TestAdvice1 before方法执行...");
}
//调用方法后的返回值 - 在方法切之后执行
@AfterReturning(pointcut = "com.spring.aop.advice.PointCut.test()", returning = "object")
public void returning(Object object){
System.out.println("###TestAdvice1方法返回之后的处理###" + (object==null ? "无数据" : object));
if (object instanceof User){
User user = (User) object;
user.setName("你的名字被修改了!");
System.out.println("TestAdvice1方法返回之后,处理完成");
}
}
@After(value = "com.spring.aop.advice.PointCut.test()")
public void after(){
System.out.println("...TestAdvice1after方法执行...");
}
//环绕,将被切的方法包围起来
@Around(value = "com.spring.aop.advice.PointCut.test()")
public Object round(ProceedingJoinPoint point) throws Throwable {
System.out.println("******TestAdvice1 around1执行******");
Object o = point.proceed();//调用对应方法
System.out.println("******TestAdvice1 around2执行******");
return o;
}
@AfterThrowing(pointcut = "com.spring.aop.advice.PointCut.test()", throwing = "e")
public void throwing(Exception e) {
System.out.println("TestAdvice1方法出现异常时执行:"+e.getMessage());
}
}
package com.spring.aop.advice;
import com.spring.aop.dao.bean.User;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 切面的工作 - 通知
*/
@Component
@Aspect
public class TestAdvice2 {
@Before(value = "com.spring.aop.advice.PointCut.test()")
public void before(){
System.out.println("...TestAdvice2 before方法执行...");
}
//调用方法后的返回值 - 在方法切之后执行
@AfterReturning(pointcut = "com.spring.aop.advice.PointCut.test()", returning = "object")
public void returning(Object object){
System.out.println("###TestAdvice2 方法返回之后的处理###" + (object==null ? "无数据" : object));
if (object instanceof User){
User user = (User) object;
user.setName("你的名字被修改了!");
System.out.println("TestAdvice2 方法返回之后,处理完成");
}
}
@After(value = "com.spring.aop.advice.PointCut.test()")
public void after(){
System.out.println("...TestAdvice2 after方法执行...");
}
//环绕,将被切的方法包围起来
@Around(value = "com.spring.aop.advice.PointCut.test()")
public Object round(ProceedingJoinPoint point) throws Throwable {
System.out.println("******TestAdvice2 around1执行******");
Object o = point.proceed();//调用对应方法
System.out.println("******TestAdvice2 around2执行******");
return o;
}
@AfterThrowing(pointcut = "com.spring.aop.advice.PointCut.test()", throwing = "e")
public void throwing(Exception e) {
System.out.println("TestAdvice2方法出现异常时执行:"+e.getMessage());
}
}
test main
package com.spring.aop.main;
import com.spring.aop.controller.UserController;
import com.spring.aop.dao.bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("springaop.xml");
UserController userController =context.getBean("userController", UserController.class);
// UserDao userDao =context.getBean("userDaoImpl", UserDaoImpl.class);
User user=new User();
user.setAge(22);
user.setName("AOP Test");
userController.addUser(user);
}
}
aop 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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- 开启注解配置 -->
<context:annotation-config/>
<!-- 启动aop自动代理-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 开启自动扫描bean,设置范围 -->
<context:component-scan base-package="com.spring.aop"/>
</beans>
执行结果:
******TestAdvice1 around1执行******
...TestAdvice1 before方法执行...
******TestAdvice2 around1执行******
...TestAdvice2 before方法执行...
添加用户,姓名:AOP Test,年龄:22
******TestAdvice2 around2执行******
...TestAdvice2 after方法执行...
###TestAdvice2 方法返回之后的处理###无数据
******TestAdvice1 around2执行******
...TestAdvice1after方法执行...
###TestAdvice1方法返回之后的处理###无数据
注意:相关aop的属性方法介绍可参考spring-aop.xsd文件。
附件pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<scope>system</scope>
<systemPath>${project.basedir}/lib/aopalliance-1.0.jar</systemPath>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<scope>system</scope>
<systemPath>${project.basedir}/lib/aspectjweaver.jar</systemPath>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
测试过程中的报错:
Exception in thread "main" org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 11 in XML document from class path resource [springaop.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 11; columnNumber: 33; cvc-complex-type.2.4.c: 通配符的匹配很全面, 但无法找到元素 'context:annotation-config' 的声明。
原因:springaop.xml文件的beans的schemaLocation引入文件中少了:
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd