前言
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).
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>


