Spring AOP 面向切面编程的技术范例

如果你需要使用lombok.jar这个软件包简化对象代码定义,

关于在CentOS8系统上如何安装lombok.jar到STS开发工具里,请参考下面唯一一张图片的说明:

AOP 可以实现在不修改源代码的情况下给程序动态统一添加功能,而不需要破坏某个操作业务模块代码的完整性

范例1:

package com.contoso;

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

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}
package com.contoso;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class FooController {
    @Autowired
    FooService foo;

    @GetMapping(path = "foo")
    public String print() {
    	return foo.saying("hello spingboot aop");
    }

}
package com.contoso;

import org.springframework.stereotype.Service;

@Service
public class FooService {
    public String saying(String content) {
        return "saying:"+content;
    }
}
package com.contoso;

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

@Component
@Aspect
public class FooAspect {
	public FooAspect() {
		System.out.println("创建FooAspect成功");
	}

	// 定义切点
	@Pointcut("execution(* *.saying(..))")
	public void say() {
	}

	//环绕通知。
	@Around("say()")
	public void sayAround(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("环绕通知开始");
		pjp.proceed();// 执行方法
		System.out.println("环绕通知结束");
	}

	@Before("say()")
	public void sayBeFore(JoinPoint joinPoint) {
		System.out.println("sayBeFore");
		System.out.println("获取连接点方法运行时的入参列表:" + joinPoint.getArgs());
		System.out.println("获取连接点的方法签名对象:" + joinPoint.getSignature());
		System.out.println("获取连接点所在的目标对象:" + joinPoint.getTarget());
	}

	@After("say()")
	public void sayAfter(JoinPoint joinPoint) {
		System.out.println("sayAfter");
	}
}

启动 spring-boot-app 控制台会打印如下信息:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.1.RELEASE)

2019-11-18 11:23:16.152  INFO 5664 --- [           main] com.contoso.Application                  : Starting Application on contoso.com with PID 5664 (/home/myth/coding/spring-boot-aop-example/target/classes started by myth in /home/myth/coding/spring-boot-aop-example)
2019-11-18 11:23:16.155  INFO 5664 --- [           main] com.contoso.Application                  : No active profile set, falling back to default profiles: default
2019-11-18 11:23:16.751  INFO 5664 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2019-11-18 11:23:16.764  INFO 5664 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 7ms. Found 0 repository interfaces.
2019-11-18 11:23:17.028  INFO 5664 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-11-18 11:23:17.403  INFO 5664 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-11-18 11:23:17.415  INFO 5664 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-11-18 11:23:17.415  INFO 5664 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.27]
2019-11-18 11:23:17.504  INFO 5664 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-11-18 11:23:17.504  INFO 5664 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1238 ms
创建FooAspect成功
2019-11-18 11:23:18.295  INFO 5664 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-11-18 11:23:18.618  INFO 5664 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-11-18 11:23:18.620  INFO 5664 --- [           main] com.contoso.Application                  : Started Application in 2.902 seconds (JVM running for 3.518)


调用api接口控制台会打印如下信息:

http://127.0.0.1:8080/foo

环绕通知开始
sayBeFore
获取连接点方法运行时的入参列表:[Ljava.lang.Object;@4edb39e5
获取连接点的方法签名对象:String com.contoso.FooService.saying(String)
获取连接点所在的目标对象:com.contoso.FooService@39b46e28
环绕通知结束
sayAfter

范例1执行后,如果你有留意的话 ,控制器返回的是空值null,而不是我们期望的内容saying:hello spingboot aop

原因是pjp.processed()执行后结果没有返回,所以sayAround(ProceedingJoinPoint pjp)方法不能没有返回值

正确的代码如下:

package com.contoso;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
 
@Component
@Aspect
public class FooAspect {
	public FooAspect() {
		System.out.println("创建FooAspect成功");
	}
 
	// 定义切点
	@Pointcut("execution(* *.saying(..))")
	public void say() {
	}
 
	//环绕通知。
	@Around("say()")
	public Object sayAround(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("环绕通知开始");
		Object object = pjp.proceed();// 执行方法
		//printArgs(pjp);
		System.out.println("环绕通知结束");
		return object;//必须要有返回值,controller控制器才会有正确内容返回,否则控制器只会返回null值。
	}
 
	@Before("say()")
	public void sayBeFore(JoinPoint joinPoint) {
		System.out.println("sayBeFore");
		System.out.println("获取连接点方法运行时的入参列表:" + joinPoint.getArgs());
		System.out.println("获取连接点的方法签名对象:" + joinPoint.getSignature());
		System.out.println("获取连接点所在的目标对象:" + joinPoint.getTarget());
	}
 
	@After("say()")
	public void sayAfter(JoinPoint joinPoint) {
		System.out.println("sayAfter");
	}
	
	public void printArgs(ProceedingJoinPoint point) throws Exception  {
		MethodSignature signature = (MethodSignature) point.getSignature();
		Method method = signature.getMethod();
		// TODO:获取请求参数
		Object[] args = point.getArgs();
		System.err.println(args[0]);
	}

}

 

范例2:

第1步:创建数据库表以及插入测试用户数据


CREATE DATABASE `testdb`;
USE `testdb`;

CREATE TABLE `sys_log` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(50) DEFAULT NULL COMMENT '用户名',
  `operation` VARCHAR(50) DEFAULT NULL COMMENT '用户操作',
  `method` VARCHAR(200) DEFAULT NULL COMMENT '请求方法',
  `params` VARCHAR(5000) DEFAULT NULL COMMENT '请求参数',
  `time` BIGINT(20) NOT NULL COMMENT '执行时长(毫秒)',
  `ip` VARCHAR(64) DEFAULT NULL COMMENT 'IP地址',
  `create_date` DATETIME DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='系统日志';

CREATE TABLE `sys_user` (
  `id` INT(20) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(100) DEFAULT NULL,
  `code` VARCHAR(10) DEFAULT NULL,
  `email` VARCHAR(200) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO `sys_user` VALUES ('2', 'jack', '10012', 'test1@136.com');
INSERT INTO `sys_user` VALUES ('3', 'cathy', '10078', 'test2@136.com');
INSERT INTO `sys_user` VALUES ('4', 'mark', '10633', 'test3@136.com');

我们使用开发工具STS 进行开发(spring-tool-suite-3.9.10)

第2步:创建Spring Starter Project项目

第3步:安装Mybatis逆向工程插件

第4步:配置依赖包

在pom.xml文件中手动增加3个依赖包(joda-time、aspectjweaver、mybatis-generator-core):

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.1.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.contoso</groupId>
	<artifactId>spring-boot-aop-example2</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-boot-aop-example2</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.1</version>
		</dependency>
		<dependency>
			<groupId>joda-time</groupId>
			<artifactId>joda-time</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
		</dependency>
		<!-- SpringBoot - MyBatis 逆向工程 -->
		<dependency>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-core</artifactId>
			<version>1.3.7</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

第5步:创建Mybatis插件逆向工程时需要的配置文件,此文件不是自动生成的,

创建空文件src/main/resources/mybatis-generator.xml,并且手动配置其内容,

这个文件可以保存一份在自己的电脑上,以后逆向工程时,稍微改一下就能直接使用啦

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <properties resource="application.yml" />
    <context id="testTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/testdb?serverTimezone=UTC" userId="root" password="dbpass">
        </jdbcConnection>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <javaModelGenerator targetPackage="com.contoso.domain" targetProject="spring-boot-aop-example2/src/main/java">
            <property name="enableSubPackages" value="false"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <sqlMapGenerator targetPackage="mappers" targetProject="spring-boot-aop-example2/src/main/resources">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.contoso.dao" targetProject="spring-boot-aop-example2/src/main/java">
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>

       <table tableName="sys_log" domainObjectName="SysLog"
        	enableCountByExample="false" 
        	enableUpdateByExample="false"  
     		enableDeleteByExample="false" 
     		enableSelectByExample="false" 
      		selectByExampleQueryId="false">
      	</table>
       <table tableName="sys_user" domainObjectName="SysUser"
        	enableCountByExample="false" 
        	enableUpdateByExample="false"  
     		enableDeleteByExample="false" 
     		enableSelectByExample="false" 
      		selectByExampleQueryId="false">
      	</table>
    </context>
</generatorConfiguration>

第6步:修改资源文件application.properties的扩展名改为application.yml,并且手动配置其内容:

server:
  port: 8080
spring:
  datasource:
      url: jdbc:mysql://127.0.0.1:3306/testdb?useSSL=false
      username: root
      password: dbpass
mybatis:
  mapper-locations: classpath*:/mappers/*.xml  

请特别注意mapper-locations的参数值的写法,参数值里面的mappers就是targetPackage的值mappers,

mappers其实是个文件夹,application.yml中的mappers-locations可千万别写错了,否则就没法逆向工程了

        <sqlMapGenerator targetPackage="mappers" targetProject="spring-boot-aop-example2/src/main/resources">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

第7步:上面的pom.xml文件早已配置好,现在使用maven install 安装依赖包,

准备为下一步开始进行逆向工程而做准备

第8步:使用Mybatis插件开始逆向工程,生成我们需要的代码和mapper文件(xml格式的)

第9步:创建以下截图中出现的软件包以及类文件

package com.contoso.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
	//value将用于存储 "具体的操作模块的操作描述"
	String value() default "";
}

package com.contoso.aspect;

import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.contoso.annotation.LogAnnotation;
import com.contoso.dao.SysLogMapper;
import com.contoso.domain.SysLog;
import com.fasterxml.jackson.databind.ObjectMapper;

@Aspect
@Component
public class LogAspect {

	private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

	@Autowired
	private SysLogMapper sysLogMapper;

	@Autowired
	private ObjectMapper objectMapper;

	// 定义切点:发生的时机 - 即一旦加了这个注解,将触发某些事情
	@Pointcut("@annotation(com.contoso.annotation.LogAnnotation)")
	public void logPointCut() {
	}

	//定义通知:环绕通知 - 执行核心任务之前 + 执行完核心任务之后 该做的事情
	@Around("logPointCut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

		long start = System.currentTimeMillis();
		// TODO:执行核心任务
		Object object = joinPoint.proceed();
		long time = System.currentTimeMillis() - start;
		saveLog(joinPoint, time);
		return object;

	}

	// TODO:保存操作日志
	private void saveLog(ProceedingJoinPoint point, Long time) throws Exception {

		log.info("开始触发-保存操作日志");
		MethodSignature signature = (MethodSignature) point.getSignature();
		Method method = signature.getMethod();
		SysLog entity = new SysLog();

		// TODO:获取请求操作的描述信息
		LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);

		if (annotation != null) {
			entity.setOperation(annotation.value());
		}

		// TODO:获取操作方法名
		String className = point.getTarget().getClass().getName();
		String methodName = signature.getName();
		entity.setMethod(className + "." + methodName + "()");

		// TODO:获取请求参数
		Object[] args = point.getArgs();
		entity.setParams(objectMapper.writeValueAsString(args[0]));

		// TODO:获取剩余参数
		entity.setTime(time);
		entity.setCreateDate(DateTime.now().toDate());
		entity.setUsername("zhengzizhi@126.com");
		entity.setIp("192.168.10.10");

		sysLogMapper.insertSelective(entity);

	}

}
package com.contoso.controller;

import javax.annotation.Resource;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.contoso.annotation.LogAnnotation;
import com.contoso.dao.SysUserMapper;
import com.contoso.domain.SysUser;
import com.contoso.dto.LogUpdateDto;
import com.contoso.enums.StatusCode;
import com.contoso.response.BaseResponse;

@RestController
@RequestMapping("/user")
public class UserController {
	@Resource
	private SysUserMapper userMapper;

	@LogAnnotation("面向切面编程的-日志操作")
	@RequestMapping(value = "update", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE })
	public BaseResponse<SysUser> update(@RequestBody LogUpdateDto dto) throws Exception {
		BaseResponse<SysUser> response = new BaseResponse<SysUser>(StatusCode.Success);
		SysUser user = new SysUser();
		user.setId(2);//模拟id=2的用户修改自己的姓名
		user.setName(dto.getName());//姓名
		user.setCode(dto.getCode());//验证码
		userMapper.updateByPrimaryKeySelective(user);
		response.setData(user);
		response.setCode(200);
		return response;
	}
}
package com.contoso.dto;

import java.io.Serializable;

public class LogUpdateDto implements Serializable {

	private static final long serialVersionUID = 1297735262193418898L;
	private String name;
	private String code;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
}
package com.contoso.enums;

public enum StatusCode {

    Success(0,"成功"),
    Fail(-1,"失败"),
    InvalidParams(201,"非法的参数!"),
    InvalidGrantType(202,"非法的授权类型");

    private Integer code;
    private String msg;

    StatusCode(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
package com.contoso.response;

import com.contoso.enums.StatusCode;

public class BaseResponse<T> {
    private Integer code; //状态码code
    private String msg;  //状态码对应的描述信息msg
    private T data; //响应数据
    public BaseResponse(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public BaseResponse(StatusCode statusCode) {
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
    }
    public BaseResponse(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    public Integer getCode() {
        return code;
    }
 
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
}

 

启动项目控制台会打印如下信息,出错的原因是自动生成的2个接口文件 ,都没有手动添加@Mapper注解


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
[32m :: Spring Boot :: [39m      [2m (v2.2.1.RELEASE)[0;39m

[2m2019-11-19 11:24:12.455[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mcom.contoso.Application                 [0;39m [2m:[0;39m Starting Application on contoso.com with PID 23512 (/home/myth/coding/spring-boot-aop-example2/target/classes started by myth in /home/myth/coding/spring-boot-aop-example2)
[2m2019-11-19 11:24:12.459[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mcom.contoso.Application                 [0;39m [2m:[0;39m No active profile set, falling back to default profiles: default
[2m2019-11-19 11:24:13.103[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36m.s.d.r.c.RepositoryConfigurationDelegate[0;39m [2m:[0;39m Bootstrapping Spring Data repositories in DEFAULT mode.
[2m2019-11-19 11:24:13.115[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36m.s.d.r.c.RepositoryConfigurationDelegate[0;39m [2m:[0;39m Finished Spring Data repository scanning in 8ms. Found 0 repository interfaces.
[2m2019-11-19 11:24:13.195[0;39m [33m WARN[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.m.s.mapper.ClassPathMapperScanner     [0;39m [2m:[0;39m No MyBatis mapper was found in '[com.contoso]' package. Please check your configuration.
[2m2019-11-19 11:24:13.382[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mtrationDelegate$BeanPostProcessorChecker[0;39m [2m:[0;39m Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
[2m2019-11-19 11:24:13.707[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.s.b.w.embedded.tomcat.TomcatWebServer [0;39m [2m:[0;39m Tomcat initialized with port(s): 8080 (http)
[2m2019-11-19 11:24:13.714[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.apache.catalina.core.StandardService  [0;39m [2m:[0;39m Starting service [Tomcat]
[2m2019-11-19 11:24:13.715[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36morg.apache.catalina.core.StandardEngine [0;39m [2m:[0;39m Starting Servlet engine: [Apache Tomcat/9.0.27]
[2m2019-11-19 11:24:13.777[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.a.c.c.C.[Tomcat].[localhost].[/]      [0;39m [2m:[0;39m Initializing Spring embedded WebApplicationContext
[2m2019-11-19 11:24:13.778[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.s.web.context.ContextLoader           [0;39m [2m:[0;39m Root WebApplicationContext: initialization completed in 1275 ms
[2m2019-11-19 11:24:13.844[0;39m [33m WARN[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mConfigServletWebServerApplicationContext[0;39m [2m:[0;39m Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'logAspect': Unsatisfied dependency expressed through field 'sysLogMapper'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.contoso.dao.SysLogMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
[2m2019-11-19 11:24:13.848[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.apache.catalina.core.StandardService  [0;39m [2m:[0;39m Stopping service [Tomcat]
[2m2019-11-19 11:24:13.879[0;39m [32m INFO[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mConditionEvaluationReportLoggingListener[0;39m [2m:[0;39m 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
[2m2019-11-19 11:24:13.974[0;39m [31mERROR[0;39m [35m23512[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.s.b.d.LoggingFailureAnalysisReporter  [0;39m [2m:[0;39m 

***************************
APPLICATION FAILED TO START
***************************

Description:

Field sysLogMapper in com.contoso.aspect.LogAspect required a bean of type 'com.contoso.dao.SysLogMapper' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'com.contoso.dao.SysLogMapper' in your configuration.

正确的添加了@Mapper注解的接口文件代码如下:

package com.contoso.dao;

import org.apache.ibatis.annotations.Mapper;

import com.contoso.domain.SysLog;

@Mapper
public interface SysLogMapper {
    int deleteByPrimaryKey(Long id);

	int insert(SysLog record);

	int insertSelective(SysLog record);

	SysLog selectByPrimaryKey(Long id);

	int updateByPrimaryKeySelective(SysLog record);

	int updateByPrimaryKey(SysLog record);

}
package com.contoso.dao;

import org.apache.ibatis.annotations.Mapper;

import com.contoso.domain.SysUser;

@Mapper
public interface SysUserMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(SysUser record);

    int insertSelective(SysUser record);

    SysUser selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(SysUser record);

    int updateByPrimaryKey(SysUser record);
}

重新启动项目成功后控制台会打印如下信息:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
[32m :: Spring Boot :: [39m      [2m (v2.2.1.RELEASE)[0;39m

[2m2019-11-19 16:59:42.720[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mcom.contoso.Application                 [0;39m [2m:[0;39m Starting Application on contoso.com with PID 30057 (/home/myth/coding/spring-boot-aop-example2/target/classes started by myth in /home/myth/coding/spring-boot-aop-example2)
[2m2019-11-19 16:59:42.724[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mcom.contoso.Application                 [0;39m [2m:[0;39m No active profile set, falling back to default profiles: default
[2m2019-11-19 16:59:43.549[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36m.s.d.r.c.RepositoryConfigurationDelegate[0;39m [2m:[0;39m Bootstrapping Spring Data repositories in DEFAULT mode.
[2m2019-11-19 16:59:43.563[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36m.s.d.r.c.RepositoryConfigurationDelegate[0;39m [2m:[0;39m Finished Spring Data repository scanning in 10ms. Found 0 repository interfaces.
[2m2019-11-19 16:59:43.949[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mtrationDelegate$BeanPostProcessorChecker[0;39m [2m:[0;39m Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
[2m2019-11-19 16:59:44.324[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.s.b.w.embedded.tomcat.TomcatWebServer [0;39m [2m:[0;39m Tomcat initialized with port(s): 8080 (http)
[2m2019-11-19 16:59:44.330[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.apache.catalina.core.StandardService  [0;39m [2m:[0;39m Starting service [Tomcat]
[2m2019-11-19 16:59:44.330[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36morg.apache.catalina.core.StandardEngine [0;39m [2m:[0;39m Starting Servlet engine: [Apache Tomcat/9.0.27]
[2m2019-11-19 16:59:44.392[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.a.c.c.C.[Tomcat].[localhost].[/]      [0;39m [2m:[0;39m Initializing Spring embedded WebApplicationContext
[2m2019-11-19 16:59:44.392[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.s.web.context.ContextLoader           [0;39m [2m:[0;39m Root WebApplicationContext: initialization completed in 1627 ms
[2m2019-11-19 16:59:45.355[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.s.s.concurrent.ThreadPoolTaskExecutor [0;39m [2m:[0;39m Initializing ExecutorService 'applicationTaskExecutor'
[2m2019-11-19 16:59:45.768[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mo.s.b.w.embedded.tomcat.TomcatWebServer [0;39m [2m:[0;39m Tomcat started on port(s): 8080 (http) with context path ''
[2m2019-11-19 16:59:45.772[0;39m [32m INFO[0;39m [35m30057[0;39m [2m---[0;39m [2m[           main][0;39m [36mcom.contoso.Application                 [0;39m [2m:[0;39m Started Application in 3.404 seconds (JVM running for 3.944)

 

[myth@contoso ~]$ mysql -uroot -pdbpass -h127.0.0.1 -e"select * from testdb.sys_log"
+----+--------------------+------------------------------------+------------------------------------------------+---------------------------------------+------+---------------+---------------------+
| id | username           | operation                          | method                                         | params                                | time | ip            | create_date         |
+----+--------------------+------------------------------------+------------------------------------------------+---------------------------------------+------+---------------+---------------------+
|  9 | zhengzizhi@126.com | 面向切面编程的-日志操作            | com.contoso.controller.UserController.update() | {"name":"jack@163.com","code":"2528"} |  234 | 192.168.10.10 | 2019-11-19 03:39:03 |
+----+--------------------+------------------------------------+------------------------------------------------+---------------------------------------+------+---------------+---------------------+
[myth@contoso ~]$ 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值