前言
在使用了SpringBoot项目中,我们能够体会到SpringBoot自动配置给我们带来的便利,它的核心思想是约定大于配置,尽管做到了绝大部分的配置。还是存在两个问题:一个是有些配置不在自动配置的范围,需要自定义配置;另一个是有些自动配置不能够很好的满足你的需要,需要对他们进行覆盖。所以我们还是经常需要使用到自定义配置,在SpringMVC的开发模式下,习惯于使用applicationContext.xml中进行相关配置。而SpringBoot推荐使用JavaConfig的方式来实现配置。
1、Spring配置
首先介绍下Spring的几种配置方式:Spring 主要提供了XML、注解、JavaConfig等三种方式实现Bean的创建和注入。
Spring有个核心的思想Ioc(控制反转),其中提到出了概念Bean,Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象。Spring容器会自动完成@bean对象的实例化。由Spring容器来负责Bean的实例化,装配和管理。
1.1 XML配置
XML用来描述Bean的配置关系,Spring从XML配置文件中读取任何类型的元数据并自动转换成相应的Java代码。使用XML来配置Bean失去编译时的类型安全检查,同时大量的XML配置使得整个项目变得更加复杂。后续不推荐使用这种方式对Bean进行管理。
1.2 注解配置
JDK1.5开始对注解进行支持,Spring提供了声明Bean的注解(如@Service、@Resource)减少很多配置量。Spring使用注解来描述Bean的配置与采用XML相比,因类注释是在一个类源代码中,可以获得类型安全检查的好处,可以良好地支持重构。
1.3 JavaConfig
从Spring 3.x开始,Spring提供了Java配置的能力。Java配置是Spring4.x推荐的配置方式,可以完全替代xml配置;Java配置也是Spring Boot推荐的配置方式。
Spring的Java配置方式是通过 @Configuration 和 @Bean 这两个注解实现的:
①、@Configuration 作用于类上,相当于一个xml配置文件;
②、@Bean 作用于方法上,相当于xml配置中的<bean>;
1.3.1 定义Bean
举例:
@Configuration public class FeignClientLogConfig { @Bean Logger QjxFeign(){ return new QjxFeignLogger(); } }
这个配置等同于下面XML中的配置:
<beans> <bean id="FeignClientLogConfig" class="com.qjx.common.log.QjxFeignLogger "/> </beans>
1.3.2 Bean依赖
可以依赖其他任意数量的Bean,如果 cacheManager依赖redisTemplate代码如下:
@Configuration @EnableCaching public class RedisCacheConfig { @Bean public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate){ CacheManager cacheManager = new RedisCacheManager(redisTemplate); return cacheManager; } }
这个配置等同于下面XML中的配置:
<beans> <bean id="cacheManager" class="com.qjx.config.RedisCacheConfig">
<property name="redisTemplate" ref="redisTemplate"></property> </bean> </beans>
注意:bean的依赖的其他的必须也是Bean,就是说依赖的这个对象,在Spring容器中一定存在。使用JavaConfig时,把依赖放置在请求参数中,容易忽略这个问题。
2、自定义配置
大多数情况下,自动配置的Bean满足模拟的需求,不用去覆盖它们。但是某些情况下,Spring Boot在自动装配的时候还不能很好的进行推断。这时,Spring Boot提供的解决方法是,覆盖自动配置的Bean。
举个例子,我们数据库配置按照安全要求是需要进行密码加密的。但是在自动装配中,是不能够做这个个性化的操作的。所以需要覆盖自动装配的Bean。
连接Redis数据库代码如下:
@Configuration @EnableCaching public class RedisCacheConfig { @Autowired private JedisConfig jedisConfig; @Bean public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate){ CacheManager cacheManager = new RedisCacheManager(redisTemplate); return cacheManager; } @Bean public RedisTemplate<String, String> redisTemplate(JedisConnectionFactory factory){ RedisTemplate<String, String> redisTemplate = new RedisTemplate<String,String>(); redisTemplate.setConnectionFactory(factory); return redisTemplate; } @Bean public JedisConnectionFactory redisConnectionFactory() { JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(); redisConnectionFactory.setHostName(jedisConfig.getHost()); redisConnectionFactory.setPort(jedisConfig.getPort()); redisConnectionFactory.setPassword(decodeStr(jedisConfig.getPassword()));//Redis密码进行解密 redisConnectionFactory.setTimeout(jedisConfig.getTimeout()); redisConnectionFactory.setPoolConfig(jedisConfig.getPoolConfig()); return redisConnectionFactory; } /** * 密码解密 * @param encodeStr */ public String decodeStr(String encodeStr) { UserAndPasswordAesBean.setSysId(); return UserAndPasswordAesBean.decrypt(encodeStr); } }
上述代码,将JedisConnectionFactory自动配置进行覆盖,在设置密码前,将配置文件中的密码使用解密方法解密。
总结:想要覆盖Spring Boot的自动配置,你所要做的仅仅是编写一个现实的配置。Spring Boot发现你的配置,随后降低自动配置的优先级,已你配置为准。
3、自定义配置的实现方式
首先,Spring Boot自动配置自带了很多配置类,每一个都能运用在你的应用程序汇中。在使用了Spring4.0的条件下设置,可以在运行时判断这个配置是该被运用还是忽略。
举个列子,Redis的自动配置:
@Bean @ConditionalOnMissingBean(RedisConnectionFactory.class) public JedisConnectionFactory redisConnectionFactory() throws UnknownHostException { return applyProperties(createJedisConnectionFactory()); }
其中JedisConnectionFactory的方法上添加了@Bean注解,在需要的时候可以配置出相应的Bean。但是上面还加了@ConditionalOnMissingBean,要求当前不存在RedisConnectionFactory类型的Bean时才生效。所有当已经有了一个Bean的时候,条件不满足,所有不会自动配置JedisConnectionFactory的Bean。