SpringAOP

优点:

  • 解藕
  • 更好的代码复用

如何使用

  • 创建maven项目,导入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.0.11.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.0.11.RELEASE</version>
    </dependency>
</dependencies>
  • 创建一个计算器接口,定义加减乘除方法

    package org.csu.utils;
    
    public interface Cal {
        public int add(int num1,int num2);
        public int sub(int num1,int num2);
        public int mul(int num1,int num2);
        public int div(int num1,int num2);
    }
  • 创建接口的实现类方法

    package org.csu.utils.impl;
    
    import org.csu.utils.Cal;
    
    public class CalImpl implements Cal {
    
        public int add(int num1, int num2) {
            System.out.println("add方法的参数是["+ num1+","+num2+"]");
            int result = num1 + num2;
            System.out.println("add方法的结果是["+ result+"]");
            return result;
        }
    
        public int sub(int num1, int num2) {
            System.out.println("sub方法的参数是["+ num1+","+num2+"]");
    
            int result = num1 - num2;
            System.out.println("sub方法的结果是["+ result+"]");
    
            return result;
        }
    
        public int mul(int num1, int num2) {
            System.out.println("mul方法的参数是["+ num1+","+num2+"]");
    
            int result = num1 * num2;
            System.out.println("mul方法的结果是["+ result+"]");
    
            return result;
        }
    
        public int div(int num1, int num2) {
            System.out.println("div方法的参数是["+ num1+","+num2+"]");
            int result = num1 / num2;
            System.out.println("div方法的结果是["+ result+"]");
    
            return result;
        }
    }

上述代码中,日志信息与业务逻辑的耦合度很高,不利于系统的维护,使用AOP可以优化。可以通过动态***来实现AOP

给业务逻辑找一个***,打印日志信息的工作交给***来做,这样的话业务代码就只需要关注自身的业务即可。

package org.csu.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class MyInvokationHandler implements InvocationHandler {
   //接受委托对象
    private Object object = null;
    //返回***对象
    public Object bind(Object object){
        this.object = object;
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName() + "的参数是"+ Arrays.toString(args));
        Object result = method.invoke(this.object,args);
        System.out.println(method.getName()+"的结果是"+result);
        return result;
    }
}

以上通过动态***的方法实现AOP的过程,复杂且不好理解。Spring对AOP进行了封装,可以用面向对象的方法来实现AOP。

Spring不用创建InvocationHandler,只需要创建一个切面对象,将所有的非业务代码放在切面对象中完成即可。Spring会根据切面类以及目标类生成一个***对象

package org.csu.utils.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class LoggerAspect {
    @Before("execution(public int org.csu.utils.impl.CalImpl.*(..))")
    public void before(JoinPoint joinPoint){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        //获取参数
        String args = Arrays.toString(joinPoint.getArgs());
        System.out.println(name +"的aop参数是"+args);


    }
}

两个注解:

  • @Aspect : 表明该类是切面类
  • @Component :把该类的对象注入到IOC容器中

spring.xml中配置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:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"

        xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 创建 SimpleDateFormat 实例并对这个实例进行实例化-->
<!--    自动扫描-->
    <context:component-scan base-package="org.csu"></context:component-scan>
<!--使得asect注解生效,为目标类自动生成***对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

context:component-scan 将 org.csu包中所有类进行扫描,如果该类同时添加了 @Component,则将该类扫描到ioc容器中,让ioc管理他的对象

aop:aspectj-autoproxy 让spring结合切面类与目标类自动生成***对象

调用aop

package org.csu.utils.test;

import org.csu.utils.Cal;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop.xml");
        //获取***对象
        Cal proxy =(Cal) applicationContext.getBean("calImpl");
        proxy.add(6,7);
    }
}