【spring boot】SpringBoot初学(6)– aop与自定义注解
前言
github: https://github.com/vergilyn/SpringBootDemo
一、AOP
1.1 pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
1.2 demo
对aop的properties配置有:
#### AOP
# spring.aop.auto=true # Add @EnableAspectJAutoProxy.
# spring.aop.proxy-target-class=false # Whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false).
这两个配置都允许注解配置: @EnableAspectJAutoProxy (proxyTargetClass = false,exposeProxy = false),默认值都是false
代码目录:

代码说明:
1. AopService:被aop增强的class。
AopAspect:aop增强的class。
AopApplication:启动、测试class。
2. 整个demo很简单,实际要用到再去细看AOP也可以。
@Component
public class AopService {
@Value("${aop.name:Dante}")
private String name; public String getMsg() {
return "Hello, " + this.name;
}
}
@Aspect
@Component
public class AopAspect {
@AfterReturning("execution(* com.vergilyn.demo.springboot.aop.*Service.*(..))")
public void afterReturning(JoinPoint joinPoint) {
System.out.println("aop @AfterReturning: " + joinPoint);
}
}
@SpringBootApplication
//开启aop支持; 可properties配置proxyTargetClass、exposeProxy
//@EnableAspectJAutoProxy //(proxyTargetClass = true,exposeProxy = false)
public class AopApplication implements CommandLineRunner {
@Autowired
private AopService aopService; public static void main(String[] args) {
SpringApplication app = new SpringApplication(AopApplication.class);
app.setAdditionalProfiles("aop");
app.run(args);
} @Override
public void run(String... args) {
System.out.println(this.aopService.getMsg());
}
}
aop.name=vergilyn #### AOP
# spring.aop.auto=true # Add @EnableAspectJAutoProxy.
# spring.aop.proxy-target-class=false # Whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false).
application-aop.properties
console输出结果:
aop @AfterReturning: execution(String com.vergilyn.demo.springboot.aop.AopService.getMsg())
Hello, vergilyn
二、自定义注解
其实我本来是要做的是:自定义注解注入Logger,所以才顺道写了一下AOP的demo。
需求:
1. 通过注解,注入Logger(org.apache.log4j.Logger)。
说明:
之前注入日志都是在每个类中写代码,ex:
public class XXclass{
private Logger log = Logger.getLogger(XXclass.class);
}
现在想通过自定义注解注入,ex:
public class XXclass{
private Logger log1 = Logger.getLogger(XXclass.class);
@Log //自定义注解
private Logger log2;
}
其中log2的效果与log1一样。
实现:
1. 可以通过aop注入。
2. 可以通过实现org.springframework.beans.factory.config.BeanPostProcessor注入;
(其实是一样的,了解spring的就知道Bean的注入都会通过BeanPostProcessor)
代码demo:
注解Log的定义
@Retention(RUNTIME)
@Target(FIELD)
@Documented
@Inherited
public @interface Log { }
注解的实现
@Component
@Aspect
public class LogInjector implements BeanPostProcessor { public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
} public Object postProcessBeforeInitialization(final Object bean,String beanName) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException,
IllegalAccessException {
// System.out.println("Logger Inject into :" + bean.getClass());
// make the field accessible if defined private
ReflectionUtils.makeAccessible(field);
if (field.getAnnotation(Log.class) != null) {
Logger log = Logger.getLogger(bean.getClass());
field.set(bean, log);
}
}
});
return bean;
}
}
启动、测试类
@SpringBootApplication
public class AnnotationApplication implements CommandLineRunner{
@Log
private Logger log; public static void main(String[] args) {
SpringApplication app = new SpringApplication(AnnotationApplication.class);
app.setAdditionalProfiles("log");
app.run(args);
} @Override
public void run(String... args) throws Exception {
System.out.println("log : " + log);
log.info("log 注解注入成功. log:" + log);
}
}
输出结果:
log : org.apache.log4j.Logger@24d31b86
2017-03-19 19:44:34.576 INFO 7688 --- [ restartedMain] ication$$EnhancerBySpringCGLIB$$52ae5e8e : log 注解注入成功. log:org.apache.log4j.Logger@24d31b86
三、扩展:spring boot之@Import、@ImportResource
缘由:由于我代码的目录结构是,一个project中根据package不同(因为spring boot默认扫描启动类所在的包,及其子包),测试spring boot的各种功能。

比如图中的*Application.class都是spring boot的启动类。然而我想把前面写的Log注解用在所有的*Application对应的项目中。
这就迁出一个问题:*Application.class只扫描所在的package及其sub-packages。从目录结构可以看到,Log并不能被别的*Application.class扫描到。
所以,要怎么解决呢?
这就需要spring boot提供的注解:@Import、@ImportResource。ex:
@SpringBootApplication
@EnableScheduling //通过@EnableScheduling注解开启对计划任务的支持
//@ImportResource(locations = "ConfigXML/annotation-scan.xml" )
@Import(value = LogInjector.class)
public class TimmerApplication {
public static void main(String[] args) {
SpringApplication.run(TimmerApplication.class, args);
}
}
对于@ImportResource需要通过xml注入bean(就是普通的spring),annotation-scan.xml:
<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:mvc="http://www.springframework.org/schema/mvc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <!-- 扫描公共组件 -->
<context:component-scan base-package="com.vergilyn.demo.annotation" /> </beans>
【spring boot】SpringBoot初学(6)– aop与自定义注解的更多相关文章
- Java Spring Boot VS .NetCore (十一)自定义标签 Java Tag Freemarker VS .NetCore Tag TagHelper
Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filter Jav ...
- Spring Boot → 08:嵌入式Servlet容器自定义
Spring Boot → 08:嵌入式Servlet容器自定义
- Java Spring Boot VS .NetCore (八) Java 注解 vs .NetCore Attribute
Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filter Jav ...
- SpringBoot 源码解析 (十)----- Spring Boot的核心能力 - 集成AOP
本篇主要集成Sping一个重要功能AOP 我们还是先回顾一下以前Spring中是如何使用AOP的,大家可以看看我这篇文章spring5 源码深度解析----- AOP的使用及AOP自定义标签 Spri ...
- Spring Boot系列——AOP配自定义注解的最佳实践
AOP(Aspect Oriented Programming),即面向切面编程,是Spring框架的大杀器之一. 首先,我声明下,我不是来系统介绍什么是AOP,更不是照本宣科讲解什么是连接点.切面. ...
- Spring Boot 2.0 教程 | AOP 切面统一打印请求日志
欢迎关注微信公众号: 小哈学Java 文章首发于个人网站 https://www.exception.site/springboot/spring-boot-aop-web-request 本节中,您 ...
- 用AOP拦截自定义注解并获取注解属性与上下文参数(基于Springboot框架)
目录 自定义注解 定义切面 获取上下文信息JoinPoint ProceedingJoinPoint 定义测试方法 测试结果 小结 AOP可以用于日志的设计,这样话就少不了要获取上下文的信息,博主在设 ...
- Spring Boot(五):Spring Boot的启动器Starter大全及自定义Starter
现有启动器Starter目录 Spring Boot应用启动器基本的一共有44种,具体如下: 1)spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和 ...
- SpringBoot框架:通过AOP和自定义注解完成druid连接池的动态数据源切换(三)
一.引入依赖 引入数据库连接池的依赖--druid和面向切面编程的依赖--aop,如下所示: <!-- druid --> <dependency> <groupId&g ...
随机推荐
- 曹工说Spring Boot源码(16)-- Spring从xml文件里到底得到了什么(aop:config完整解析【上】)
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- Codeforces 1092 D2 Great Vova Wall (Version 2) (栈)
题意: 给一排砖,每列的高度$a_i$,问是否可以放1*2的砖,使得n列高度一样,砖只能横着放 思路: 每两个相邻的高度相同的砖可以变成大于等于它的高度的任意高度 所以像这样的 123321 是不满足 ...
- 量子计算机编程(一)——QPU编程
今天要给大家介绍的是这本书<Programming Quantum Computers -- Essential Algorithms and Code Samples>,主要讲如何在量子 ...
- Github搜索技巧-如何使用github找到自己感兴趣的项目(转载)
Github现在不仅仅作为一个版本控制工具,更是一个开源的仓库,里面不但有优秀的开源代码,电子书,还有一些五花八门的项目,有些国家的法律也放在上面,作为程序员如何找到自己感兴趣的项目就非常重要了! 欢 ...
- 编辑crontab添加Linux计划任务
在做实验楼的比赛时的题目 用到了crontable 1. 为用户shiyanlou添加一个计划任务 2. 每天凌晨2点定时执行 3. 将/var/log/dpkg.log /var/log/mysql ...
- Bound Method and Unbound Method - 绑定方法 与 非绑定方法
Bound Method and Unbound Method 通常有两种方法对类的方法(instance.method)/属性(class.attribute)进行引用, 一种称做 Bound Me ...
- Python3(二) 表示‘组’的概念与定义
现实世界中总存在一组一组的事物, 一.列表的定义 type(['hello','world',1,9,True,False]) = <class 'list'> type([[1,2,3, ...
- python 实现 跳一跳游戏 代码解析
这个代码实现的是 手动点击起点 和 终点 ,程序自动判断距离.触屏时间 完成跳跃 原理(摘自项目说明页面):1. 将手机点击到“跳一跳”小程序界面:2. 用Adb 工具获取当前手机截图,并用a ...
- css架构技巧
1. 写一个reset.css 用于清除浏览器标签默认样式并定义全局样式,这样就不会因为浏览器默认样式出现问题,因为不同浏览器的默认样式还是不一样的
- MySQL常用语法总结
一,学习mysql的前戏 1:基础入门命令 show databases: #查看当前MySQL中的所有数据库 create 数据库名: #创建新的数据库 use 数据库名: #使用该数据库 show ...