AOP它是一种思想,并非是Spring 特有,Spring只是支持了AOP的框架之一,它是方法级别的AOP框架,主要是以某个类的某个方法为连接点,实现动态代理。
在Spring中有4种方式实现AOP,在使用时基本是以 @AspectJ 注解 为主,XML配置为辅实现AOP。
XML配置AOP@AspectJ注解实现AOP
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>6.0.3version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>5.3.21version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>6.0.3version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.3.21version>
dependency>
创建dao,模拟从数据库中获取数据
@Bean("userList")
public List<User> getUserList(){
List<User> userList = new ArrayList<>();
userList.add(new User(1,"用户1","123456",false));
userList.add(new User(2,"用户2","234567",false));
userList.add(new User(3,"用户3","345678",false));
userList.add(new User(4,"用户4","456789",false));
userList.add(new User(5,"用户5","567890",false));
return userList;
}
@Repository
public class ProxyTestUserDao {
@Resource
private List<User> userList;
//改
public void update(User user) {
boolean exists = true;
for (int i=0; i<userList.size(); i++){
if(user.getUserId().equals(userList.get(i).getUserId())){
exists = false;
userList.set(i,user);
break;
}
}
if(exists){
System.out.println("没有此用户");
}
}
//删
public void delete(int id) {
boolean exists = false;
for (int i=0; i<userList.size(); i++){
if(id == userList.get(i).getUserId()){
exists = true;
userList.remove(i);
break;
}
}
if(!exists){
System.out.println("没有此用户");
}
}
//查
public User select(int id) {
for (User user : userList) {
if (id == user.getUserId()) {
return user;
}
}
return null;
}
public List<User> selectAll() {
return userList;
}
//增加
public void insert(User user) {
int id = userList.get(userList.size()-1).getUserId();
id += 1;
user.setUserId(id);
userList.add(user);
System.out.println("增加成功");
}
}
创建service,用其作为连接点
@Service
public class ProxyTestUserServiceImpl implements ProxyTestUserService {
@Autowired
private ProxyTestUserDao proxyTestUserDao;
@Override
public void update(User user) {
proxyTestUserDao.update(user);
}
@Override
public void delete(int id) {
proxyTestUserDao.delete(id);
}
@Override
public User select(int id) {
return proxyTestUserDao.select(id);
}
@Override
public List<User> selectAll() {
return proxyTestUserDao.selectAll();
}
@Override
public void insert(User user) {
proxyTestUserDao.insert(user);
}
}
创建切面
public class UserServiceInterceptor implements Interceptor {
/**
* 前置通知
*/
public void before(JoinPoint joinPoint) {
//获取连接点的名字
String methodName = joinPoint.getSignature().getName();
//获取目标方法的实参信息
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("前置通知,方法名:"+methodName+",参数:"+args);
}
/**
* 后置通知
*/
public void after(JoinPoint joinPoint) {
//获取连接点的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("后置通知,方法名:"+methodName);
}
/**
* 返回通知
*/
public void afterReturning(JoinPoint joinPoint, Object result) {
//获取连接点的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("返回通知,方法名:"+methodName);
}
/**
* 异常通知
*/
public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
//获取连接点的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("异常通知,方法名:"+methodName+",异常:"+ex);
}
/**
* 环绕通知
*/
public Object around(ProceedingJoinPoint point){
System.out.println("环绕通知开始");
//获取连接点的名字
String methodName = point.getSignature().getName();
//获取连接点的参数
String args = Arrays.toString(point.getArgs());
System.out.println("环绕通知,方法名:"+methodName+",参数:"+args);
Object o = null;
try {
System.out.println("环绕通知:目标对象方法执行之前");
//目标对象(连接点)方法的执行
o = point.proceed();
System.out.println("环绕通知:目标对象方法返回值之后");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("环绕通知:目标对象方法出现异常时");
} finally {
System.out.println("环绕通知:目标对象方法执行完毕");
}
return o;
}
}
在XML文件中配置
<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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="interceptor" class="com.yu.spring.aspect.UserServiceInterceptor"/>
<aop:config>
<aop:aspect id="interceptor" ref="interceptor">
<aop:pointcut id="service" expression="execution(* com.yu.spring.service.impl.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="service"/>
<aop:after-returning method="afterReturning" returning="result" pointcut-ref="service"/>
<aop:after method="after" pointcut-ref="service"/>
<aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="service"/>
<aop:around method="around" pointcut-ref="service"/>
aop:aspect>
aop:config>
beans>
测试

实现AOP的主流方式,它的常用注解:
1、@Aspect:用于表明一个类为切面
2、@Before("execution(* com.yu.service.impl.UserServiceImpl.*(..))"):将一个方法表示为前置通知,并设置切入点
3、@After("execution()"):后置通知
4、@AfterThrowing("execution()"):发生异常后执行
5、@AfterReturning("execution()"):无异常时执行
6、@Around:环绕通知
切点:execution()表达式
execution:执行真实对象的方法时触发
*:任意返回类型的方法
com.yu.service.impl.UserServiceImpl:真实类的全限定名
*:写真实对象中具体拦截的方法(*是所有)
(..):任意参数
Aspectj的指示器
1、arg():限制连接点匹配参数为指定类型
2、@args():限制连接点匹配参数为指定注解标注的执行方法
3、execution:匹配连接点,最常用
4、this():限制连接点匹配AOP代理的bean,引用为指定类型的类
5、target:限制连接点匹配被代理对象为指定类型
6、within():限制连接点匹配的包
7、annotation:限制匹配带有指定注解的连接点
Service、dao等不变
创建切面,使用上面的几种注解
@Aspect
@Component
public class UserServiceImplAspect {
/**
* 前置通知
*/
@Before("execution(* com.yu.spring.service.impl.ProxyTestUserServiceImpl.*(..))")
public void before(JoinPoint joinPoint) {
//获取连接点的名字
String methodName = joinPoint.getSignature().getName();
//参数
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("前置通知(注解),方法名:"+methodName+",参数:"+args);
}
/**
* 后置通知
*/
@After("execution(* com.yu.spring.service.impl.ProxyTestUserServiceImpl.*(..))")
public void after(JoinPoint joinPoint) {
//获取连接点的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("后置通知(注解),方法名:"+methodName);
}
/**
* 返回通知
*/
@AfterReturning(value = "execution(* com.yu.spring.service.impl.ProxyTestUserServiceImpl.*(..))" , returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
//获取连接点的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("返回通知(注解),方法名:"+methodName);
}
/**
* 异常通知
*/
@AfterThrowing(value ="execution(* com.yu.spring.service.impl.ProxyTestUserServiceImpl.*(..))", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
//获取连接点的名字
String methodName = joinPoint.getSignature().getName();
System.out.println("异常通知(注解),方法名:"+methodName+",异常:"+ex);
}
/**
* 环绕通知
*/
@Around("execution(* com.yu.spring.service.impl.ProxyTestUserServiceImpl.*(..))")
public Object around(ProceedingJoinPoint point){
System.out.println("环绕通知开始(注解)");
String methodName = point.getSignature().getName();
String args = Arrays.toString(point.getArgs());
System.out.println("环绕通知(注解),方法名:"+methodName+",参数:"+args);
Object o = null;
try {
System.out.println("环绕通知(注解):目标对象方法执行之前");
//目标对象(连接点)方法的执行
o = point.proceed();
System.out.println("环绕通知(注解):目标对象方法返回值之后");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("环绕通知(注解):目标对象方法出现异常时");
} finally {
System.out.println("环绕通知(注解):目标对象方法执行完毕");
}
return o;
}
}
在主配置类使用注解开启aop
@Configuration
@ComponentScan("com.yu.spring")
//支持处理标记有 AspectJ 的@Aspect注释的组
@EnableAspectJAutoProxy
public class AOPConfig {
}
测试,通过配置类

使用Spring的aip接口实现:
测试一下:
service层
public class StudentServiceImpl implements StudentService {
@Override
public void learning() {
System.out.println("正在学习");
}
}
前置通知和后置通知类
public class BeforeAdvice implements MethodBeforeAdvice {
/**
* @param method:目标对象的方法
* @param objects:参数
* @param o:目标对象
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置通知执行了"+o.getClass().getName()+"的"+method.getName()+"方法");
}
}
public class MyAfterLog2 implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行"+method.getName()+"方法后,返回结果为:"+returnValue);
}
}
xml配置
<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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="studentService" class="com.yu.service.impl.StudentServiceImpl"/>
<bean id="afterAdvice" class="com.yu.aopaip.AfterAdvice"/>
<bean id="beforeAdvice" class="com.yu.aopaip.BeforeAdvice"/>
<aop:config>
<aop:pointcut id="point" expression="execution(* com.yu.service.impl.StudentServiceImpl.*(..))"/>
<aop:advisor advice-ref="afterAdvice" pointcut-ref="point"/>
<aop:advisor advice-ref="beforeAdvice" pointcut-ref="point"/>
aop:config>
beans>
测试
public class AppTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring2.xml");
StudentService service = (StudentService)context.getBean("studentService");
service.learning();
}
}
ProxyFactoryBean是Spring环境中给指定的bean创建代理的一种方式,
service层
public class StudentServiceImpl implements StudentService {
@Override
public void learning() {
System.out.println("正在学习");
}
}
XML方式
前置通知和后置通知类
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置通知执行"+method.getName()+"方法后,返回结果为:"+o);
}
}
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置通知执行了"+o.getClass().getName()+"的"+method.getName()+"方法");
}
}
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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="studentService" class="com.yu.service.impl.StudentServiceImpl"/>
<bean id="afterAdvice" class="com.yu.aopaip.AfterAdvice"/>
<bean id="beforeAdvice" class="com.yu.aopaip.BeforeAdvice"/>
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="studentService"/>
<property name="interceptorNames">
<list>
<value>afterAdvice</value>
<value>beforeAdvice</value>
</list>
</property>
</bean>
</beans>
获取proxyFactoryBean
public class AppTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring2.xml");
StudentService service = (StudentService)context.getBean("proxyFactoryBean");
service.learning();
}
}
注解
在@Configuration中注册前置、后置通知,和proxyFactoryBean
@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class ExplainConfiguration {
@Bean
public StudentService service(){
return new StudentServiceImpl();
}
@Bean
public MethodBeforeAdvice beforeAdvice() {
return new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置通知执行了"+o.getClass().getName()+"的"+method.getName()+"方法");
}
};
}
//注册一个后置通知
@Bean
public AfterReturningAdvice afterAdvice() {
return new AfterReturningAdvice(){
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置通知执行"+method.getName()+"方法后,返回结果为:"+o);
}
};
}
//注册ProxyFactoryBean
@Bean
public ProxyFactoryBean service1Proxy() {
//1.创建ProxyFactoryBean
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
//2.设置目标对象的bean名称
proxyFactoryBean.setTarget(service());
//3.设置拦截器的bean名称列表,此处2个(advice1和advice2)
proxyFactoryBean.setInterceptorNames("beforeAdvice", "afterAdvice");
return proxyFactoryBean;
}
}
获取ProxyFactoryBean测试
public class AppTest {
@Test
public void test(){
ApplicationContext context = new AnnotationConfigApplicationContext(ExplainConfiguration.class);
StudentService service = (StudentService)context.getBean("service1Proxy");
service.learning();
}
}