(026)Spring Boot之aop

  aop即面向切面的编程,将业务逻辑代码和琐碎逻辑代码分开,达到重用或者解耦的目的。springboot中添加完依赖即默认启用了aop。

  starter-aop依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

  贴出完整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.edu.spring</groupId>
    <artifactId>springboot_web</artifactId>
    <version>1.0.0</version>

    <name>springboot_web</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>

</project>
View Code

  springboot中aop有两个配置:spring.aop.auto和spring.aop.proxy-target-class,请看源码:

  spring.aop.auto默认是true,默认启动aop。

  spring.aop.proxy-target-class默认是true,默认使用cglib动态代理。

  (一)基于jdk的动态代理实现,必须同时满足两个条件

  (1)application.properties文件中设置spring.aop.proxy-target-class=false

spring.aop.proxy-target-class=false

  (2)必须有接口类

  IUserDao.java

package com.edu.spring.springboot;

public interface IUserDao {
    public void add(String username,String password);
}
View Code

  UserDao.java

package com.edu.spring.springboot;

import org.springframework.stereotype.Component;

@Component
public class UserDao implements IUserDao {

    public void add(String username,String password){
        System.out.println("add [username="+username+",password="+password+"]");
    }
}
View Code

  LogAspect.java,使用@Aspect、@Before、@After注解

package com.edu.spring.springboot;

import java.util.Arrays;

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

@Aspect
@Component
public class LogAspect {

    @Before("execution(* com.edu.spring.springboot..*.*(..))")
    public void log(){
        System.out.println("before method log done");
    }
    
    @After("execution(* com.edu.spring.springboot..*.*(..))")
    public void afterLog(JoinPoint point){
        System.out.println("after method log done "+point.getTarget().getClass()+",args: "+Arrays.asList(point.getArgs())+", method: "+point.getSignature());
    }
}
View Code

  App.java

package com.edu.spring.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class App    
{ 
    public static void main(String[] args) throws Exception{
        ConfigurableApplicationContext context=SpringApplication.run(App.class, args); 
        System.out.println(context.getBean(IUserDao.class).getClass());
        context.getBean(IUserDao.class).add("sl","1234");
        context.close();
    }
} 
View Code

  运行结果如下:

  (二)基于cglib的动态代理实现。可以使用接口,也可以不用接口,spring.aop.proxy-target-class=true或者去掉该配置,运行结果如下:

   说明:LogAspect是切面类,封装了横切关注点,使用@Aspect标记,并且装配到spring容器中。

    @Before是前置通知,调用add方法前先执行

    @After是后置通知,调用完add方法后执行

    参数execution(* com.edu.spring.springboot..*.*(..))表示该包(或者其子包)下的任何类中的任何方法都会被动态代理。

    JoinPoint类中封装了被代理的对象,包括目标类、方法、参数。前置通知、后置通知都可以使用JoinPoint。

原文地址:https://www.cnblogs.com/javasl/p/11966667.html