Spring AOP

发布时间:2024年01月05日

为什么要学习AOP?

  • 案例 :有一个接口Service有一个addUser方法,在调用addUser(被调用时打印调用前的毫秒数与调用后的毫秒数),其实现为:
@Service
public class UserServiceImpl implements UserService {
	
    @Autowired
    private UserDao userDao;

    public void addUser(){
        System.out.println("方法开始时间:"+new Date());
        userDao.addUser();
        System.out.println("方法结束时间:"+new Date());
    }
}
  • 问题 :假如有有一万个service类,要求每个方法执行前打印日志,执行后打印日志;输出日志的逻辑还是无法复用

AOP概述

AOP:全称是Aspect Oriented Programming即:面向切面编程。

简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对程序进行增强:权限校验,日志记录,性能监控,事务控制.

代理(Proxy)模式

 1)静态代理
            角色:
                公共接口:Star
                真实角色:RealStar(周杰伦.唱歌)
                代理角色:ProxyStar(宋吉吉.面谈.订机票.签合同.[调周杰伦唱歌].收尾款)
                客户类:Client(小孩.调宋吉吉)

            缺陷:1. 代理类和实现类实现了相同的接口,这样就出现了大量的代码重复。
                  2. 代理对象只服务于一种类型的对象。如果要服务多类型的对象,例如代码是只为UserService类的访问提供了代理,但是还要为其他类如DeptService类提供代理的话,就需要我们再次添加代理DeptService的代理类。        
2)jdk动态代理
            角色:
                公共接口:Star
                真实角色:RealStar(周杰伦.唱歌)
                代理工厂:ProxyFactroy{生成ProxyStar(宋吉吉.面谈.订机票.签合同.[调周杰伦唱歌].收尾款)}
                客户类:Client(小孩.调宋吉吉)
3)Cglib动态代理


cglib与动态代理最大的区别就是:

使用jdk动态代理的对象必须实现一个接口
使用cglib代理的对象则无需实现接口
cglib和jdk动态代理的区别:cglib真实角色没有接口

AOP相关术语

  1. 连接点(joinpoint)
    被截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法。
  2. 切入点(pointcut)
    切入点是指我们要对哪些连接点进行拦截的定义
  3. 通知(advice)
    所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
  4. 切面(aspect)
    是切入点和通知的结合
  5. 引介(introduction)
    是一种特殊的通知,在不修改代码的前提下,引介可以在运行期为类动态地添加一些方法或字段
  6. 目标对象(Target)
    要代理的目标对象(要增强的类)
  7. 织入(weave)
  8. 代理(Proxy)
    一个类被AOP织入增强之后,就产生一个代理类
    将增强应用到目标的过程将advice应用到target的过程
    在这里插入图片描述

Spring的AOP配置

创建工程

在这里插入图片描述

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.by</groupId>
    <artifactId>Spring_AOP_Xml</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Spring常用依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
         <!--支持切点表达式 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
    </dependencies>
</project>
dao
/**
 * 持久层实现类
 */
public class UserDaoImpl implements UserDao {

    @Override
    public void addUser(){
        System.out.println("insert into tb_user......");
    }
}
service
/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;
    
    public void setUserDao(UserDao userDao){
        this.userDao=userDao;
    }
	
    @Override
    public void addUser(){
        userDao.addUser();
    }
}
.applicationContext.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
       			   http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <bean id="userDao" class="com.by.dao.UserDaoImpl"></bean>
    <bean id="userService" class="com.by.service.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>
</beans>
web
/**
 * 模拟表现层
 */
public class Client {
    public static void main(String[] args) {
        ApplicationContext ac = 
            new ClassPathXmlApplicationContext("applicationContext.xml");
        //使用对象
        UserService userService = ac.getBean("userService",UserService.class);
        System.out.println(userService.getClass());
        userService.addUser();
    }
}

增强

创建工程

image-20211009103820786
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.by</groupId>
    <artifactId>Spring_AOP_Xml</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Spring常用依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
         <!--支持切点表达式 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
    </dependencies>
</project>
dao
/**
 * 持久层实现类
 */
public class UserDaoImpl implements UserDao {

    @Override
    public void addUser(){
        System.out.println("insert into tb_user......");
    }
}
service
/**
 * 业务层实现类
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;
    
    public void setUserDao(UserDao userDao){
        this.userDao=userDao;
    }
	
    @Override
    public void addUser(){
        userDao.addUser();
    }
}
applicationContext.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
       			   http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <bean id="userDao" class="com.by.dao.UserDaoImpl"></bean>
    <bean id="userService" class="com.by.service.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>
</beans>
web
/**
 * 模拟表现层
 */
public class Client {
    public static void main(String[] args) {
        ApplicationContext ac = 
            new ClassPathXmlApplicationContext("applicationContext.xml");
        //使用对象
        UserService userService = ac.getBean("userService",UserService.class);
        System.out.println(userService.getClass());
        userService.addUser();
    }
}

增强

  1. 创建增强类

    package com.by.advice;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    
    import java.util.Date;
    
    public class MyLogAdvice {
    
        //前置通知
        public void before(){
            System.out.println("前置通知");
        }
    
        //后置通知【try】
        public void afterReturning(){
            System.out.println("后置通知");
        }
    
        //异常通知【catch】
        public void afterThrowing(){
            System.out.println("异常通知");
        }
    
        //最终通知【finally】
        public void after(){
            System.out.println("最终通知");
        }
    
        //环绕通知
        public void around(ProceedingJoinPoint joinPoint){
            try {
                System.out.println("方法执行前的环绕通知");
                joinPoint.proceed();
                System.out.println("方法执行后的环绕通知");
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }
    

aop的核心概念

    切点(pintcut):要增强的方法,eg:add()、update()
    通知/增强(advice):要搞的事情,eg:日志
        前置通知:aop:before
        后置通知:aop:after-returning【try】
        最终通知:aop:after【finally】
        异常通知:aop:after-throwing【catch】
        环绕通知:aop:around

相当于下面的try{}:

   try{
                ...
                return aop:after-returning
            }catch(Exception e){
                ...
                aop:after-throwing
            }finally{
                ...
                aop:after
            }
    切面(aspect):把增强应用到切点上
4、切点表达式
    格式:execution([修饰符] 返回值 报名.类名.方法名(参数))
    eg:execution(* com.by.service.*.*(..))

5、基于xml的aop配置
    1)pom.xml
        spring-context、spring-aspects、slf4j-log4j12
    2)advice
        public class MyLogAdvice {

            public void before(){
                System.out.println("前置通知....");
            }
        }
    2)aop
        <!--增强(advice)-->
        <bean id="myLogAdvice" class="com.by.advice.MyLogAdvice"></bean>

        <aop:config>
                <!--切点(pintcut)-->
                <aop:pointcut id="pointcut" expression="execution(* com.by.service.*.*(..))"/>
                <aop:aspect ref="myLogAdvice">
                            <aop:before method="before" pointcut-ref="pointcut"></aop:before>
                </aop:aspect>
        </aop:config>
文章来源:https://blog.csdn.net/w2144217940/article/details/135412422
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。