【spring boot】SpringBoot初學(6)– aop與自定義注解


前言

  github: https://github.com/vergilyn/SpringBootDemo

一、AOP

  官方demo:https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-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
    代碼目錄:

      image

    代碼說明:

      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的各種功能。

image

  比如圖中的*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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM