说说以下几个注解的含义
1.@Configuration 此注解的用义是让一个类成为一个配置类,它与 @Bean 注解一起使用(一般用在类中的方法上面),可以用于生成一系列的 Bean .它们是用来简单基于 xml 配置 Bean 的注解。可以这样说,一个类上面 @Configuration 就相当于一个 定义 很多Bean 的 xml 文件。
2.@ConfigurationProperties 此注解的用义是让一个类成为一个注入了 propeties 变量的配置类,一般与 @Component 和 @PropertySource 一起使用,例如:
@Component @PropertySource("classpath:application.properties") @ConfigurationProperties(prefix="hrService")
public class HRConfig意思是,HRConfig 是一个装配了 propeties 的配置类(@ConfigurationProperties),装配变量的文件是 classpath:application.properties ,(@PropertySource(...)),读取文件中变量的规则是,所有以 hrService 为前缀的变量, 可以对外提供读取配置变量的服务(@Component)。
上面的配置其实可以在 Spingboot 中简化为
@Component @ConfigurationProperties(prefix="hrService")因为 Springboot 中 classpath:application.properties 是默认加载的配置文件。
@ConfigurationProperties 此注释从字面上来理解,可以设置配置的属性,使被装配类有不同的行为.例如,可以传入 prefix,ignoreUnknowFields 等等,以达到装配行为多样化。其实它并不真正具体一个对外提供配置的能力,@ConfigurationProperties 只是规定了一个类如何成为一个配置服务类,但并不使它真正成为一个配置服务类。使它具备这种能力也即使它成为一个 Bean,@Conponent 就能做到,@EnableConfigurationProperties 也能做取。
3.@EnableConfigurationProperties 允许任意一个类具有对外提供配置的能力。它与 @Bean 的方式不同,@Bean 是配置在类本身上,一劳永逸,一旦配置,任何地方都可以注入。而 @EnableConfigurationProperties 是配置在希望使用此配置服务的那个类上面。这样就可以实现可拔插。下面拷贝一份代码以说明:
@ConfigurationProperties(
prefix = "fps",
ignoreUnknownFields = true
)
@Data
public class FpsProperties {
private String host="localhost";
private int port=7008;
private String username;
private String password;
private String orgid="99996";
private int connectTimeout=10000;
private int connectRequestTimeout=10000;
private int socketTimeout=120000;//相当于读超时
private int retryCount=3;//重试次数
private boolean fpsEnabled=true;
}
//-------------------------------------------------------------------------------
@Configuration
@EnableConfigurationProperties({FpsProperties.class})
@ConditionalOnClass({FpsClient.class})
@ConditionalOnProperty(
prefix = "fps",
name = {"enabled"},
matchIfMissing = true
)
@Slf4j
public class FpsAutoConfiguration {
@Autowired
private FpsProperties fpsProperties;
@Bean
@ConditionalOnMissingBean
@ConfigurationProperties(
prefix = "fps"
)
public FpsService fpsService() {
FpsServiceImpl fpsService = new FpsServiceImpl(fpsProperties.getUsername(), fpsProperties.getPassword(), fpsProperties.getHost(), fpsProperties.getPort(), fpsProperties.getOrgid(), fpsProperties.getConnectRequestTimeout(), fpsProperties.getConnectTimeout(), fpsProperties.getSocketTimeout());
return fpsService;
}
}
首先,@configuration 表示 FpsAutoConfiguration 类是一个可生成多个 Bean 的配置器。@EnableConfigurationProperties({FpsProperties.class}) 表示使 FpsProperties 这个类拥有对“我”提供配置的能力。类里面的 @Autowired 就把这种配置能力注入进来了。@ConditionalOnClass({FpsClient.class}) 表示当整个 jvm 中存在 FpsClient 这个类时,本 @Configuration 才生效,否则不生效。当时看这个配置非常疑惑,如果 FpsClient 这个类不存在,此行代码应该会立即报错,何谈加载到 jvm 中去运行呢?解释一下,@conditionalOnClass 一般是在库中使用的,假设库工程是 A,有上面的代码。另有一个关联工程 B,A 中没有 FpsClient 类,而 B 中有,让 A 工程依赖于 B,将 A 打包,A.jar 作为一个库对外发布。此时,A.jar 是没有 FpsClient 类的定义的。此时,有一个客户工程,付费了,想使用 A.jar ,而 C 没有定义 FpsClient 类,所以 A.jar 中的上述配置就不会生效,因此,C 在运行时,就不会承担 A 里面产生的 Bean 的负担。就这是热拔插的意思。所以 @ConditionalOnClass 是为了完成这件事情的。
@ConditionalOnProperty 与 @ConditionalOnClass 目的一致,逻辑上是且的关系,只要 @ConditionalOnProperty 中规定的条件没有满足,整个 @Configuration 就不生效。上面的配置中,规定了配置变量 fps.enabled=true 时,@Configuration 才生效。
一般情况下,若变量是 fps.x.y.z.enabled,则上面要写为:prefix="fps.x.y.z", name={"enabled"}。这是因为 name 一定是最终的名字,而不含有任何前缀。
后面类里面的,@Bean 就会很熟悉了,表示定义一个 Bean 生成的条件,依赖的变量和生成的步骤。@ConditionalOnMissingBean 表示此 Bean 生成的规则:只有当这个类的 Bean 没有生成时,才会去生成 Bean. @ConfigurationProperties 其实是多余的,因为后面的代码直接使用了 FpsProperties 去取值.
上面生成 FpsServiceImpl 的 Bean 其实可以更简单:
FpsServiceImpl fpsService = new FpsServiceImpl();//前提是有无参构造方法
此时 @ConfigurationProperties 表示去FpsProperties 中找变量的值,还是默认配置文件 application.properties 中按 prefix = fps 去读呢。这个问题可能没有意义,首先要明确一点,所有配置类的配置加载器是同一个,不可能存在不同的值,至于存在同名的多个配置文件,加载的是哪一个就要具体看了,一般是后面加载的会替换前面加载的。因此,上面的问题就不用回答的。
另外,使用了此注解的类所在的包及子包下面的类也默认使用了此注解。若将此注解应用到根目录包下面的类,则所有类也都应用了此注解。所以此注解的使用一般要放在最高级的根目录类上面。
关于这个注解,最后再举一个例:
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class MyBatisConfig {
// @Value("${spring.datasource.encode-password}")
// private String encodePassword;
@Autowired
private DataSourceProperties properties;
//这个配置会加载所有spring.datasource配置注入DataSource对象,未加载会有问题。
@Bean
@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
public DataSource dataSource() {
// Assert.isNull(this.properties.getPassword(), "必须为空否则,加密密码会被覆盖");
DataSourceBuilder factory = DataSourceBuilder
.create(this.properties.getClassLoader())
.driverClassName(this.properties.getDriverClassName())
.url(this.properties.getUrl()).username(this.properties.getUsername())
.password(properties.getPassword());
if (this.properties.getType() != null) {
factory.type(this.properties.getType());
}
BasicDataSource basicDataSource= (BasicDataSource)factory.build();
basicDataSource.setMaxTotal(150);
basicDataSource.setMaxWaitMillis(5000);
return basicDataSource;
}
@Bean(name = "sqlSessionFactory")
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setTypeAliasesPackage("com.******.entity");
//分页插件
PageHelper pageHelper = new PageHelper();
Properties properties = new Properties();
properties.setProperty("reasonable", "true");
properties.setProperty("supportMethodsArguments", "true");
properties.setProperty("returnPageInfo", "check");
properties.setProperty("params", "count=countSql");
pageHelper.setProperties(properties);
//添加插件
bean.setPlugins(new Interceptor[]{pageHelper});
//添加XML目录
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return bean.getObject();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
4.@EnableAutoconfiguration 这个注解作用在于让 Spring Boot 根据应用所声明的依赖来对 Spring 框架进行自动配置,比较智能的是,它还根据 classpath 中的 jar 包推断需要引入哪些注解/ Bean ,另外,使用了此注解的类所在的包及子包下面的类也默认使用了此注解。若将此注解应用到根目录包下面的类,则所有类也都应用了此注解,这也是最通常的做法,实际上, @SpingBootApplication 注解就使用了这个注解。详细的说明可以参看 EnableAutoconfiguration 注解实现文件的说明。
@Configuration @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) public class MyConfiguration { }