一、@Enable* 启用某个特性的注解

1、EnableConfigurationProperties

回顾属性装配

application.properties中添加

tomcat.host=192.168.2.1
tomcat.port=8080

增加属性类TomcatProperties

package com.lhx.spring.springboot_enable;

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 + "]";
} }

在App中添加代码

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

查看注解SpringBootApplication,其中使其起作用的是@EnableAutoConfiguration,继续追踪代码,其实生效的是:@EnableConfigurationProperties

故以上代码配置

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

注解:是用来启用一个特性的,特性可以把配置文件的属性注入到Bean类中,一般和@ConfigurationProperties一起使用

2、EnableAsync

增加一个异步打印类

package com.lhx.spring.springboot_enable;

import java.util.concurrent.TimeUnit;

import org.springframework.stereotype.Component;

@Component
public class Jeep implements Runnable { @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();
} } }

在App中调用

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

发现此时并没有异步执行

需要在异步打印类中启用@EnableAsync,并在具体方法上标注@Async即可

package com.lhx.spring.springboot_enable;

import java.util.concurrent.TimeUnit;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component; @Component
@EnableAsync
public class Jeep implements Runnable { @Override
@Async
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println("---------------"+i);
TimeUnit.SECONDS.sleep(1);
}
} catch (Exception e) {
e.printStackTrace();
} } }

这时在调用App方法即可异步

注解:启用异步,一般和Async一起使用

二、原理

1、注解Import

  跟踪EnableAsync或EnableConfigurationProperties进入发现,共同注解@Import。  

/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.context.annotation; 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; /**
* Indicates one or more {@link Configuration @Configuration} classes to import.
*
* <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
* Allows for importing {@code @Configuration} classes, {@link ImportSelector} and
* {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component
* classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
*
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
* accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
* injection. Either the bean itself can be autowired, or the configuration class instance
* declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
* navigation between {@code @Configuration} class methods.
*
* <p>May be declared at the class level or as a meta-annotation.
*
* <p>If XML or other non-{@code @Configuration} bean definition resources need to be
* imported, use the {@link ImportResource @ImportResource} annotation instead.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.0
* @see Configuration
* @see ImportSelector
* @see ImportResource
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import { /**
* {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
* or regular component classes to import.
*/
Class<?>[] value(); }

  import作用:Indicates one or more {@link Configuration @Configuration} classes to import.

  用来导入一个或多个类(bean被spring容器托管)、或者配置类(配置类里面的Bean都会被spring容器托管)

  Enable*其实就是使用了Import,Import其实就是导入了配置类

示例

新建一个User类

package com.lhx.spring.springboot_enable;

public class User {

}

新建一个Role类

package com.lhx.spring.springboot_enable;

public class Role {

}

使用Import在App中导入

package com.lhx.spring.springboot_enable;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import; @ComponentScan
@Import(User.class)
public class App2 {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(App2.class, args);
System.out.println(context.getBean(User.class));
System.out.println(context.getBean(Role.class));
context.close();
}
}

可以看到导入一个,另一个会失败

也可以导入配置类

package com.lhx.spring.springboot_enable;

import org.springframework.context.annotation.Bean;

public class MyConfiguration {
@Bean
public Runnable createRunnable() {
return () -> {
};
} @Bean
public Runnable createRunnable2() {
return () -> {
};
}
}

导入

@Import({User.class,Role.class,MyConfiguration.class})  

2、ImportSelector接口

作用:方法selectImports的返回值,必须是一个class(全称),改class会被Spring容器托管

/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.context.annotation; import org.springframework.core.type.AnnotationMetadata; /**
* Interface to be implemented by types that determine which @{@link Configuration}
* class(es) should be imported based on a given selection criteria, usually one or more
* annotation attributes.
*
* <p>An {@link ImportSelector} may implement any of the following
* {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective
* methods will be called prior to {@link #selectImports}:
* <ul>
* <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
* <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}</li>
* <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}</li>
* <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}</li>
* </ul>
*
* <p>ImportSelectors are usually processed in the same way as regular {@code @Import}
* annotations, however, it is also possible to defer selection of imports until all
* {@code @Configuration} classes have been processed (see {@link DeferredImportSelector}
* for details).
*
* @author Chris Beams
* @since 3.1
* @see DeferredImportSelector
* @see Import
* @see ImportBeanDefinitionRegistrar
* @see Configuration
*/
public interface ImportSelector { /**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata); }

示例

创建一个MyImportSelector

package com.lhx.spring.springboot_enable;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata; public class MyImportSelector implements ImportSelector { @Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {"com.lhx.spring.springboot_enable.User",Role.class.getName(),MyConfiguration.class.getName()};
} }

在App中使用

package com.lhx.spring.springboot_enable;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportSelector; @ComponentScan
@Import(MyImportSelector.class)
public class App3 {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(App3.class, args);
System.out.println(context.getBean(User.class));
System.out.println(context.getBean(Role.class));
System.out.println(context.getBeansOfType(Runnable.class)); context.close();
}
}

增加一个Enable开头的注解,可以结合注解使用

增加一个注解EnableLog

package com.lhx.spring.springboot_enable;

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(MyImportSelector2.class)
public @interface EnableLog {
String name();
}

增加一个ImportSelector实现MyImportSelector2

package com.lhx.spring.springboot_enable;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata; public class MyImportSelector2 implements ImportSelector { @Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
System.out.println(importingClassMetadata.getAllAnnotationAttributes(EnableLog.class.getName()));
return new String[] { "com.lhx.spring.springboot_enable.User", Role.class.getName(),
MyConfiguration.class.getName() };
} }

使用

package com.lhx.spring.springboot_enable;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportSelector; @ComponentScan
@EnableLog(name="my annon")
public class App4 {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(App4.class, args);
System.out.println(context.getBean(User.class));
System.out.println(context.getBean(Role.class));
System.out.println(context.getBeansOfType(Runnable.class)); context.close();
}
}

3、ImportBeanDefinitionRegistrar

作用:方法的参数有一个BeanDefinitionRegistry,BeanDefinitionRegistry可以用来网Spring容器中注入Bean,如此,就可以动态注入bean

/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.context.annotation; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.core.type.AnnotationMetadata; /**
* Interface to be implemented by types that register additional bean definitions when
* processing @{@link Configuration} classes. Useful when operating at the bean definition
* level (as opposed to {@code @Bean} method/instance level) is desired or necessary.
*
* <p>Along with {@code @Configuration} and {@link ImportSelector}, classes of this type
* may be provided to the @{@link Import} annotation (or may also be returned from an
* {@code ImportSelector}).
*
* <p>An {@link ImportBeanDefinitionRegistrar} may implement any of the following
* {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective
* methods will be called prior to {@link #registerBeanDefinitions}:
* <ul>
* <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
* <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}
* <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}
* <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}
* </ul>
*
* <p>See implementations and associated unit tests for usage examples.
*
* @author Chris Beams
* @since 3.1
* @see Import
* @see ImportSelector
* @see Configuration
*/
public interface ImportBeanDefinitionRegistrar { /**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry); }

自定义实现MyImportBeanDefinitionRegistrar

package com.lhx.spring.springboot_enable;

import org.springframework.beans.factory.support.AbstractBeanDefinition;
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 MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("user",
BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition()); registry.registerBeanDefinition("role",
BeanDefinitionBuilder.rootBeanDefinition(Role.class).getBeanDefinition());
registry.registerBeanDefinition(MyConfiguration.class.getName(),
BeanDefinitionBuilder.rootBeanDefinition(MyConfiguration.class).getBeanDefinition()); } }

此时就可以在EnableLog上使用

package com.lhx.spring.springboot_enable;

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(MyImportSelector2.class)
@Import(MyImportBeanDefinitionRegistrar.class)
public @interface EnableLog {
String name();
}

示例

代码地址:https://github.com/bjlhx15/spring-boot.git 中的 springboot-enable即可

007-Spring Boot-@Enable*注解的工作原理-EnableConfigurationProperties、ImportSelector、ImportBeanDefinitionRegistrar的更多相关文章

  1. Spring的@Enable*注解的工作原理

    转自:https://blog.csdn.net/chengqiuming/article/details/81586948 一 列举几个@Enable*注解的功能 @EnableAspectJAut ...

  2. Spring Boot @Enable*注解源码解析及自定义@Enable*

      Spring Boot 一个重要的特点就是自动配置,约定大于配置,几乎所有组件使用其本身约定好的默认配置就可以使用,大大减轻配置的麻烦.其实现自动配置一个方式就是使用@Enable*注解,见其名知 ...

  3. Spring高级特性之三:@Enable*注解的工作原理

    Spring Boot中阐述热插拔技术的时候,简单地提及@Enable*注解.随着多种框架的应用及深入了解,@Enable*这个注解在各种框架中应用相当普及. 那么@Enable*注解工作原理是怎么样 ...

  4. Spring高级话题-@Enable***注解的工作原理

    出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy注解 激活Aspect自动代理 & ...

  5. springBoot @Enable*注解的工作原理

    使用注解实现异步 RunnableDemo类 package com.boot.enable.bootenable; import org.springframework.scheduling.ann ...

  6. @Enable*注解的工作原理

    @EnableAspectJAutoProxy @EnableAsync @EnableScheduling @EnableWebMv @EnableConfigurationProperties @ ...

  7. 深度剖析Spring Boot自动装配机制实现原理

    在前面的分析中,Spring Framework一直在致力于解决一个问题,就是如何让bean的管理变得更简单,如何让开发者尽可能的少关注一些基础化的bean的配置,从而实现自动装配.所以,所谓的自动装 ...

  8. EnableAutoConfiguration注解的工作原理(org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.bean.MyConfig)

    EnableAutoConfiguration注解的工作原理(org.springframework.boot.autoconfigure.EnableAutoConfiguration=core.b ...

  9. Spring Boot常用注解总结

    Spring Boot常用注解总结 @RestController和@RequestMapping注解 @RestController注解,它继承自@Controller注解.4.0之前的版本,Spr ...

随机推荐

  1. http协议中常见的状态码以及请求方式,http协议的组成

    请求状态码: 2xxx:表示请求成功,例如200. 3xxx:表示请求被重定向,表示完成请求,需要进一步操作,例如 302. 4xxx:表示请求错误,例如:404,资源没有找到. 5xxx:表示服务器 ...

  2. C语言scanf的返回值

    #include <stdio.h> int main(void) { long num; long sum = 0L; int status; printf("Please e ...

  3. JSP页面包含其他页面的三种方式及区别

    一. <%@ include file="header.inc"%> 该指令在编译之前先读入指定的页面中的内容(并不对动态内容求值),融合后的完整页面再被整体的转换为一 ...

  4. 看CLRS 对B树的浅显理解

    定义及特点: 每个结点有n个关键字和n+1个指向子结点的指针,即有n+1个孩子结点. n个关键字按非递减的顺序存储. 最小度数t>=2,除了根结点的所有内部结点(非叶结点)的孩子数>=t且 ...

  5. Linux shell 批量验证端口连通性

    工作中会遇到验证到某某服务器端口是否连通,如果IP或端口多时,用shell还是很省时省力的,看下面的脚本: #!/bin/bash # #database check #set -o nounset ...

  6. vue 之 双向绑定原理

    一.实现双向绑定 详细版: 前端MVVM实现双向数据绑定的做法大致有如下三种: 1.发布者-订阅者模式(backbone.js) 思路:使用自定义的data属性在HTML代码中指明绑定.所有绑定起来的 ...

  7. C\C++下获取系统进程或线程ID(转)

    在程序开发时有时需要获取线程和进程ID以分析程序运行 ()windows下获取进程或线程ID 通过调用系统提供的GetCurProcessId或GetNowThreadID来获取当前程序代码运行时的进 ...

  8. Node Buffer 利用 slice + indexOf 生成 split 方法

    demo let buf = Buffer.from('你你我们我你们'); Buffer.prototype.split = function (seq) { let arr=[]; let len ...

  9. 前端每日实战:122# 视频演示如何用纯 CSS 创作一个苹果系统的相册图标

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/zJKwbO 可交互视频 此视频是可 ...

  10. CF1242B. 0-1 MST

    题目大意 有一个n个点的完全图,上面有m条边的权值为1,其余为0 求MST n,m<=10^5 题解 方法一: 维护一个点集,表示当前MST中的点 一开始任意加一个点 对于一个未加入的点,如果和 ...