1. 程式人生 > >Spring Boot @Enable*註解工作原理

Spring Boot @Enable*註解工作原理

一、讀取配置檔案

--application.properties
tomcat.host=192.168.1.1
tomcat.port=8080
package vip.fkandy.model;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "tomcat")
public class TomcatProperties {
	private String host;
	private String port;

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public String getPort() {
		return port;
	}

	public void setPort(String port) {
		this.port = port;
	}

	@Override
	public String toString() {
		return "TomcatProperties [host=" + host + ", port=" + port + "]";
	}

}
package vip.fkandy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import vip.fkandy.model.TomcatProperties;

/**
 * @author chenjianfei
 */
//@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan
public class Application {

	public static void main(String[] args) {
		ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
		System.out.println(context.getBean(TomcatProperties.class));
	}
}

@SpringBootApplication中用來讀取配置檔案的主要註解是@@EnableAutoConfiguration(AutoConfigurationImportSelector)和
@ComponentScan

二、Spring Boot使用非同步

package vip.fkandy;

import java.util.concurrent.TimeUnit;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class MyRunnable implements Runnable {

	@Async
	@Override
	public void run() {
		try {
			for (int i = 0; i < 10; i++) {
				System.out.println("------" + i);
				TimeUnit.SECONDS.sleep(1);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
package vip.fkandy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;

import vip.fkandy.model.TomcatProperties;

/**
 * @EnableAutoConfiguration 用來啟用一個特性:可以把配置檔案的屬性注入到Bean裡面
 * @EnableAsync 用來啟用非同步執行特性,在需要非同步執行的方法上新增@Async註解
 * @author chenjianfei
 *
 */
@SpringBootApplication
@EnableAsync
public class Application {

	public static void main(String[] args) {
		ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
		System.out.println(context.getBean(TomcatProperties.class));
		context.getBean(Runnable.class).run();
		System.out.println("-------end-------");
	}
}

非同步操作類:AsyncConfigurationSelector

三、ImportSelector原理 讀取註解內容

package vip.fkandy.config;

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

import org.springframework.context.annotation.Import;

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MyImportSelector.class)
public @interface EnableLog {
	String name();
}
package vip.fkandy.config;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

import vip.fkandy.model.User;

public class MyImportSelector implements ImportSelector {

	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		/**
		 * 這裡可以獲取到註解的詳細資訊,然後根據資訊去動態返回需要被Spring 容器管理的bean
		 */
		System.out.println("---" + importingClassMetadata.getAnnotationAttributes(EnableLog.class.getName()));

		return new String[] { User.class.getName() };
	}

}
package vip.fkandy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;

import vip.fkandy.config.EnableLog;
import vip.fkandy.model.TomcatProperties;

/**
 * @EnableAutoConfiguration 用來啟用一個特性:可以把配置檔案的屬性注入到Bean裡面
 * @EnableAsync 用來啟用非同步執行特性,在需要非同步執行的方法上新增@Async註解
 * @author chenjianfei
 *
 */
@SpringBootApplication
@EnableAsync
@EnableLog(name = "my spring boot test annotation")
public class Application {

	public static void main(String[] args) {
		ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
		System.out.println(context.getBean(TomcatProperties.class));
		context.getBean(Runnable.class).run();
		System.out.println("-------end-------");
	}
}

四、ImportBeanDefinitionRegistrar原理(無返回值,需要自己通過BeanDefinitionRegistry注入bean)

package vip.fkandy.model;

public class User {

}
package vip.fkandy.config;

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

import org.springframework.context.annotation.Import;

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MyImportBeanDefinitionRegistrar.class)
public @interface EnableLog {
	String name();
}
package vip.fkandy.config;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

import vip.fkandy.model.User;

/**
 * 向Spring容器注入User
 * 
 * @author chenjianfei
 *
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(User.class);
		BeanDefinition beanDefinition = builder.getBeanDefinition();
		registry.registerBeanDefinition("user", beanDefinition);
	}

}
package vip.fkandy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;

import vip.fkandy.config.EnableLog;
import vip.fkandy.model.User;

/**
 * @EnableAutoConfiguration 用來啟用一個特性:可以把配置檔案的屬性注入到Bean裡面
 * @EnableAsync 用來啟用非同步執行特性,在需要非同步執行的方法上新增@Async註解
 * @author chenjianfei
 *
 */
@SpringBootApplication
@EnableAsync
@EnableLog(name = "my spring boot test annotation")
public class Application {

	public static void main(String[] args) {
		ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
		System.out.println(context.getBean(User.class));
		System.out.println("-------end-------");
	}
}

五、Enable和Import結合使用demo

package vip.fkandy.config;

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

import org.springframework.context.annotation.Import;

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EchoImportBeanDefinitionRegistrar.class)
public @interface EnableEcho {
	String[] packages();
}
package vip.fkandy.config;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class EchoImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		Map<String, Object> annotationAttributes = importingClassMetadata
				.getAnnotationAttributes(EnableEcho.class.getName());
		String[] packArray = (String[]) annotationAttributes.get("packages");
		List<String> packages = Arrays.asList(packArray);
		System.out.println("packages :" + packages);
		BeanDefinitionBuilder beanBuilder = BeanDefinitionBuilder.rootBeanDefinition(EchoBeanPostProcessor.class);
		beanBuilder.addPropertyValue("packages", packages);
		registry.registerBeanDefinition(EchoBeanPostProcessor.class.getName(), beanBuilder.getBeanDefinition());
	}

}
package vip.fkandy.config;

import java.util.List;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class EchoBeanPostProcessor implements BeanPostProcessor {
	private List<String> packages;

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		for (String pack : packages) {
			if (bean.getClass().getName().startsWith(pack)) {
				System.out.println("echo bean :" + bean.getClass().toGenericString());
			}
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
	}

	public List<String> getPackages() {
		return packages;
	}

	public void setPackages(List<String> packages) {
		this.packages = packages;
	}
}
package vip.fkandy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;

import vip.fkandy.config.EnableEcho;
import vip.fkandy.config.EnableLog;

/**
 * @EnableAutoConfiguration 用來啟用一個特性:可以把配置檔案的屬性注入到Bean裡面
 * @EnableAsync 用來啟用非同步執行特性,在需要非同步執行的方法上新增@Async註解
 * @author chenjianfei
 *
 */
@SpringBootApplication
@EnableAsync
@EnableLog(name = "my spring boot test annotation")
@EnableEcho(packages = "vip.fkandy.model")
public class Application {

	public static void main(String[] args) {
		ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
		System.out.println("-------end-------");
	}
}

日誌


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

2018-10-06 09:07:05.425  INFO 13196 --- [           main] vip.fkandy.Application                   : Starting Application on DESKTOP-6FVEB35 with PID 13196 (D:\STS_4.0\workspace\00\springboot-2\target\classes started by chenjianfei in D:\STS_4.0\workspace\00\springboot-2)
2018-10-06 09:07:05.444  INFO 13196 --- [           main] vip.fkandy.Application                   : No active profile set, falling back to default profiles: default
2018-10-06 09:07:05.598  INFO 13196 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.ser[email protected]389b0789: startup date [Sat Oct 06 09:07:05 CST 2018]; root of context hierarchy
packages :[vip.fkandy.model]
2018-10-06 09:07:07.821  INFO 13196 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2018-10-06 09:07:07.860  INFO 13196 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-10-06 09:07:07.861  INFO 13196 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.34
2018-10-06 09:07:07.879  INFO 13196 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [D:\jdk1.8.0_161\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;D:\jdk1.8.0_161\jre\bin;D:/jdk1.8.0_161/bin/../jre/bin/server;D:/jdk1.8.0_161/bin/../jre/bin;D:/jdk1.8.0_161/bin/../jre/lib/amd64;D:\app\chenjianfei\product\11.2.0\client_1\bin;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;D:\jdk1.8.0_161\bin;D:\apache-maven-3.5.2\bin;D:\Git\cmd;D:\gradle-4.5\bin;D:\scala-2.12.6\bin;D:\zookeeper-3.4.12\bin;D:\Program Files\TortoiseSVN\bin;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;C:\Users\chenjianfei\AppData\Local\Microsoft\WindowsApps;C:\Users\chenjianfei\AppData\Local\GitHubDesktop\bin;D:\STS_4.0;;.]
2018-10-06 09:07:08.116  INFO 13196 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-10-06 09:07:08.117  INFO 13196 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2522 ms
2018-10-06 09:07:08.221  INFO 13196 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
2018-10-06 09:07:08.227  INFO 13196 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-10-06 09:07:08.228  INFO 13196 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-10-06 09:07:08.228  INFO 13196 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-10-06 09:07:08.228  INFO 13196 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
echo bean :public class vip.fkandy.model.TomcatProperties
echo bean :public class vip.fkandy.model.User
2018-10-06 09:07:08.467  INFO 13196 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-10-06 09:07:08.758  INFO 13196 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.ser[email protected]389b0789: startup date [Sat Oct 06 09:07:05 CST 2018]; root of context hierarchy
2018-10-06 09:07:08.876  INFO 13196 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-10-06 09:07:08.878  INFO 13196 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-10-06 09:07:09.035  INFO 13196 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-10-06 09:07:09.037  INFO 13196 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-10-06 09:07:09.238  INFO 13196 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-10-06 09:07:09.288  INFO 13196 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-10-06 09:07:09.295  INFO 13196 --- [           main] vip.fkandy.Application                   : Started Application in 4.433 seconds (JVM running for 5.256)
-------end-------