Spring学习--AOP的实现

之前我谈到过动态代理:Spring学习-动态代理
动态代理里面很好地体现了AOP的思想,即面向切面编程:在不修改代码影响原有业务逻辑时,新增其他功能。
那么,在Spring中,如何实现AOP呢?

方法一:使用Spring的API接口

首先,需要新导入一个依赖:

<dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
</dependency>

接着,我们编写一个接口及其实现类:

package com.yyl.service;

/**
 * @Author: LongLongA
 * @Description:
 * @Date: Created in 9:51 2020/12/14
 */
public interface UserService {
    void add();
    void delete();
    void update();
    void select();
}

package com.yyl.service;

/**
 * @Author: LongLongA
 * @Description:
 * @Date: Created in 9:51 2020/12/14
 */
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("add...");
    }

    @Override
    public void delete() {
        System.out.println("delete...");
    }

    @Override
    public void update() {
        System.out.println("update...");
    }

    @Override
    public void select() {
        System.out.println("select...");
    }
}

这时,我们设想一个应用场景:需要一个日志类,在每次接口方法被调用时,打印日志。
之前的时候,我们可以自己写一个关于接口的代理类来完成上述业务,与此同时,Spring框架也实现了相关接口:
首先,编写一个日志类,然后实现Spring中提供的接口:

package com.yyl.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * @Author: LongLongA
 * @Description:
 * @Date: Created in 10:08 2020/12/14
 */
public class MyLog implements MethodBeforeAdvice {
    @Override
    /*
    * method : 要执行的目标对象的方法
    * args : 方法所需参数
    * target: 被执行的目标(被切入的目标)
    *
    * */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被调用");
    }
}



这里,MethodBeforeAdvice接口表明该日志类需要执行的方法在指定业务之前。声明后,before里面的函数会在target对象中的method方法执行之前被调用。
之后我们再编写一个日志类:

package com.yyl.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

/**
 * @Author: LongLongA
 * @Description:
 * @Date: Created in 10:18 2020/12/14
 */
public class MyLog2 implements AfterReturningAdvice {//该接口用于在target执行之后调用
    @Override
    // returnValue : 该参数用于接收返回值
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
    }
}

以上事情做完后,我们需要在Spring容器中注册这些类,并且来配置AOP:

<?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
        https://www.springframework.org/schema/aop/spring-aop.xsd">


    <!--注册Bean-->
    <bean id="userServiceImpl" class="com.yyl.service.UserServiceImpl"/>
    <bean id="myLog" class="com.yyl.log.MyLog"/>
    <bean id="myLog2" class="com.yyl.log.MyLog2"/>

    <!--配置AOP:需要导入aop的约束-->
    <aop:config>
        <!--
        定义切入点,即需要在哪个位置执行
        execution(要执行的类的位置)
        -->
        <aop:pointcut id="pointcut1" expression="execution(* com.yyl.service.UserServiceImpl.*(..))"/>

        <!--
            定义切入的方法,将其与切入点关联
            advice-ref属性值为切入方法的Id
            pointcut-ref属性值为切入点的id
        -->
        <aop:advisor advice-ref="myLog" pointcut-ref="pointcut1"/>
        <aop:advisor advice-ref="myLog2" pointcut-ref="pointcut1"/>
    </aop:config>

</beans>

下面是测试代码:

import com.yyl.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author: LongLongA
 * @Description:
 * @Date: Created in 11:35 2020/12/14
 */
public class MyTest {
    public static void main(String[] args) {
        //获取Spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
         //重点!!!:动态代理代理的是接口,所以返回值必须为接口,而不是它的实现类!!!
        UserService userServiceImpl = (UserService)context.getBean("userServiceImpl");
        userServiceImpl.add();
        userServiceImpl.delete();
        userServiceImpl.update();
        userServiceImpl.select();
    }
}

测试结果:
Spring学习--AOP的实现
重点来了!!!!!
动态代理代理的是接口,所以返回值必须为接口,而不是它的实现类!!!
所以在此代码:
UserService userServiceImpl = (UserService)context.getBean("userServiceImpl");
返回值一定要是UserService接口,而不是它的实现类!!!
以后只要记住一点:“动态代理代理的是接口,而不是实现类”

方法二:未完待续。。。

上一篇:hyperf依赖注入和控制反转


下一篇:Spring07:AOP