Spring (6) AOP

AOP: The full name is Aspect Oriented Programming, namely: Aspect Oriented Programming.

Simply put, it is to extract the repetitive code of our program. When it needs to be executed, it uses dynamic proxy technology to enhance our existing methods without modifying the source code.

How to use AOP in Spring to implement dynamic proxy and simplify the code

Step1: File import coordinates

  <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
  </dependency>
   <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
 

The aspectjweaver here prepares for the following entry point expression

Step2: Configure related bean.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">


<!--配置Service,Service中需要用到Dao-->
    <bean id="IUserService" class="com.imis.service.impl.UserServiceImpl">
        <property name="iUserDao" ref="IUserDao"></property>
    </bean>
<!--配置Dao,Dao中又继承BaseDao,BaseDao中需要用到QueryRunner-->
    <bean id="IUserDao" class="com.imis.dao.impl.UserDaoImpl">
        <property name="queryRunner" ref="runner"></property>
    </bean>

<!--    <context:component-scan base-package="com.imis"></context:component-scan>-->
<!--QueryRunner配置,注入数据源,由于QueryRunner中没有关于数据源的set方法,但提供了构造函数,所以用构造函数的方法来注入-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>

<!--  配置数据源  -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/firstmybatis?serverTimezone=Asia/Shanghai"/>
        <property name="user" value="root"/>
        <property name="password" value="zhengyunyu524"/>
    </bean>
<!--  把log放进ioc容器中  -->
    <bean id="logger" class="com.imis.log.Log">

    </bean>
<!--配置aop-->
    <aop:config>
<!--    配置切面指定类    -->
        <aop:aspect id="logAdvice" ref="logger">
<!--      配置切面指定类的方法及要切入的类的方法      -->
<!--       前置     -->
            <aop:before method="before" pointcut="execution(public * com.imis.service.impl.UserServiceImpl.queryAll())"></aop:before>
<!--        后置    -->
            <aop:after-returning method="after" pointcut="execution(public * com.imis.service.impl.UserServiceImpl.queryAll())"></aop:after-returning>
<!--         异常   -->
            <aop:after-throwing method="afterexception" pointcut="execution(public * com.imis.service.impl.UserServiceImpl.queryAll())"></aop:after-throwing>
<!--         最终   -->
            <aop:after method="end" pointcut="execution(public * com.imis.service.impl.UserServiceImpl.queryAll())"></aop:after>

        </aop:aspect>
    </aop:config>
</beans>

XML-based AOP configuration steps in spring
1. Give the notification bean to spring to manage
2. Use the aop:config tag to indicate the start of AOP configuration
3. Use the aop: aspect tag to indicate the configuration aspect
id attribute: it provides a unique aspect for the aspect Identification
ref attribute: is the Id of the designated notification class bean.
4. Use the corresponding label inside the aop: aspect label to configure the type of notification

        aop:before:表示配置前置通知
        aop:after-returning:后置通知
        aop:after-throwing:异常通知
        aop:after:最终通知
        method属性:用于指定Logger类中哪个方法是前置通知

Pointcut attribute: used to specify the pointcut expression, the meaning of the expression refers to which methods in the business layer are enhanced

    切入点表达式的写法:
       关键字:execution(表达式)
       表达式:访问修饰符  返回值  包名.包名.包名...类名.方法名(参数列表)
       标准的表达式写法:
       public void com.itheima.service.impl.AccountServiceImpl.saveAccount()

Sample Log code:

public class Log {
    
    

    public void before(){
    
    
        System.out.println("执行前");
    }
    public void after(){
    
    
        System.out.println("执行后");
    }
    public void afterexception(){
    
    
        System.out.println("有异常");
    }
    public void end(){
    
    
        System.out.println("最终结束");
    }
}

At this point, we run the queryAll method on the basis of configuring AOP, and we can get the following results

执行前
[User{
    
    username='zzy', userid=1}, User{
    
    username='yxx', userid=2}, User{
    
    username='ss', userid=3}]
执行后
最终结束

How to write the entry point expression:

关键字:execution(表达式)
表达式:
    访问修饰符  返回值  包名.包名.包名...类名.方法名(参数列表)
标准的表达式写法:
     public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略
    void com.itheima.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符,表示任意返回值
    * com.itheima.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
    * *.*.*.*.AccountServiceImpl.saveAccount())
包名可以使用..表示当前包及其子包
    * *..AccountServiceImpl.saveAccount()
类名和方法名都可以使用*来实现通配
     * *..*.*()
参数列表:
    可以直接写数据类型:
        基本类型直接写名称           int
        引用类型写包名.类名的方式   java.lang.String
        可以使用通配符表示任意类型,但是必须有参数
        可以使用..表示有无参数均可,有参数可以是任意类型
全通配写法:
    * *..*.*(..)

实际开发中切入点表达式的通常写法:
    切到业务层实现类下的所有方法
    * com.itheima.service.impl.*.*(..)

General pointcut expression

 <aop:pointcut id="query" expression="execution(public * com.imis.service.impl.UserServiceImpl.queryAll())"/>
<!--      配置切面指定类的方法及要切入的类的方法      -->
<!--       前置     -->
<aop:before method="before" pointcut-ref="query"></aop:before>

Guess you like

Origin blog.csdn.net/weixin_45925906/article/details/112846530