美文网首页springboot工作总结
Springboot的自动装配

Springboot的自动装配

作者: 二月_春风 | 来源:发表于2017-07-20 23:43 被阅读142次

    不积跬步,无以至千里。

    先看一个 org.springframework.context.annotation.Condition接口,接口定义如下,定义了返回布尔类型的matches方法。

    public interface Condition {
        boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
    }
    

    实现这个接口可以得到二个对象ConditionContextAnnotatedTypeMetadata
    ,这个接口也是从spring4.0开始出现的。

    再看一个@Conditional注解,这个注解也是从spring4.0出现的。

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Conditional {
        Class<? extends Condition>[] value();
    
    }
    

    这个接口和注解干嘛用的,先不详细说明,先看一个demo。

    demo

    定义一个接口

    package com.zhihao.miao.beans;
    
    public interface EncodingConvert {
    }
    

    其二个实现类:

    package com.zhihao.miao.beans;
    
    public class GBKEncodingConvert implements EncodingConvert{
    }
    
    package com.zhihao.miao.beans;
    
    public class UTF8EncodingConvert implements EncodingConvert{
    }
    

    配置类,

    @SpringBootConfiguration
    public class MyConfig {
    
        @Bean
        public UTF8EncodingConvert createUTF8Encoding(){
            return new UTF8EncodingConvert();
        }
    
        @Bean
        public GBKEncodingConvert createGBKEncoding(){
            return new GBKEncodingConvert();
        }
    }
    

    第一篇博客我们知道UTF8EncodingConvert对象和GBKEncodingConvert对象都会纳入到spring容器中管理。

    主测试类:

    package com.zhihao.miao;
    
    import com.zhihao.miao.beans.EncodingConvert;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    
    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
            System.out.println(context.getBeansOfType(EncodingConvert.class));
            context.close();
        }
    }
    

    启动,打印结果:

    {createUTF8Encoding=com.zhihao.miao.beans.UTF8EncodingConvert@15043a2f, createGBKEncoding=com.zhihao.miao.beans.GBKEncodingConvert@4a83a74a}
    

    很明显符合我们的期望。

    现在有需求如下,我从配置文件中读取配置project.encodingUTF-8时,系统自动装配UTF8EncodingConvert这个对象,读取到project.encodingGBK时,系统自动装配GBKEncodingConvert。其实看到博客的结束就知道有更简单的实现。

    定义二个类实现上面所说的Condition接口,其重写方法matches,返回布尔类型。

    package com.zhihao.miao.condition;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    
    public class GBKCondition implements Condition{
    
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String encoding = context.getEnvironment().getProperty("project.encoding");
            logger.info("encoding==="+encoding);
            if(encoding != null){
                return "gbk".equals(encoding.toLowerCase());
            }
    
            return false;
        }
    }
    
    package com.zhihao.miao.condition;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class UTF8Condition implements Condition{
    
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String encoding = context.getEnvironment().getProperty("project.encoding");
            logger.info("encoding==="+encoding);
            if(encoding != null){
                return "utf-8".equals(encoding.toLowerCase());
            }
            return false;
        }
    }
    

    之前的MyConfig类修改如下:

    package com.zhihao.miao.beans;
    
    import com.zhihao.miao.condition.GBKCondition;
    import com.zhihao.miao.condition.UTF8Condition;
    import org.springframework.boot.SpringBootConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    
    @SpringBootConfiguration
    public class MyConfig {
    
        @Bean
        @Conditional(UTF8Condition.class)
        public UTF8EncodingConvert createUTF8Encoding(){
            return new UTF8EncodingConvert();
        }
    
        @Bean
        @Conditional(GBKCondition.class)
        public GBKEncodingConvert createGBKEncoding(){
            return new GBKEncodingConvert();
        }
    }
    

    @Conditional的参数是一个实现Condition接口的实现类,如果实现类返回true表示自动装配这个@Conditional注解修改的方法的对象,反之亦然。

    当然@Conditional注解也可以在修改类,比如说修饰当前类MyConfig,那么当注解参数返回true的时候,则当前类下的所有对象都会自动装配,反之亦然。

    配置文件application.properties如果配置了

    project.encoding=utf-8
    

    则打印结果为

    {createUTF8Encoding=com.zhihao.miao.beans.UTF8EncodingConvert@4c60d6e9}
    

    如果application.properties如果配置为

    project.encoding=gbk
    

    则打印结果为:

    {createGBKEncoding=com.zhihao.miao.beans.GBKEncodingConvert@72cc7e6f}
    

    springboot依赖提供的一些自动装配的@Conditional

    上面自定义了@Conditional实现,也就说当某种情况下满足时去自动装配对象。自定义类实现org.springframework.context.annotation.Condition接口,然后配置@Conditional注解进行根据条件来自动装配。

    springboot提供的@Conditional**注解

    spring-boot-autoconfigure依赖的condition包下提供了一些默认实现好的的@Conditional**注解,

    org.springframework.boot.autoconfigure.condition.ConditionalOnBean:
    存在某个bean已经被spring 容器装配的时候,当前bean也自动装配。
    org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean:
    某个bean没有被spring容器装配的时候自定装配当前类。

    org.springframework.boot.autoconfigure.condition.ConditionalOnClass:
    当classpath路径下有这个类依赖的时候自动装配,没有的时候不装配
    org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass与上面相反

    org.springframework.boot.autoconfigure.condition.ConditionalOnExpression
    当指定的SpEL表达式返回true的时候自动装配,

    org.springframework.boot.autoconfigure.condition.ConditionalOnJava
    当前jvm的版本号是**的时候进行自动装配。

    org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication
    当前环境不是web环境的时候装配
    org.springframework.boot.autoconfigure.conditionConditionalOnWebApplication
    当前环境是web环境的时候自动装配.

    org.springframework.boot.autoconfigure.condition.ConditionalOnResource
    当某个资源存在的时候自动装配。
    org.springframework.boot.autoconfigure.condition.ConditionalOnProperty:
    当配置文件存在的时候,或者当配置文件等于某个值的时候自动装配。

    写一个demo测试一下:

    @ConditionalOnProperty

    定义一普通类UserConfig

    @SpringBootConfiguration
    public class UserConfig {
    
        /**
         * 表示在application.properties中配置的属性等于某个值的时候(havingValue配置的值),Runnable这个类自动状态,
         * 实例名为createRunnable,缺省(matchIfMissing)的时候也自动装套
         */
        @Bean
        @ConditionalOnProperty(name="runnable.enabled",havingValue = "true",matchIfMissing = true)
        public Runnable createRunnable(){
            return () -> {};
        }
    }
    

    application.properties中配置了runnable.enabled属性,

    runnable.enabled=true
    

    启动Application类,

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

    打印结果:

    {createRunnable=com.zhihao.miao.config.UserConfig$$Lambda$7/510276116@79207381}
    

    @ConditionalOnClass

    定义一普通类UserConfig

    @SpringBootConfiguration
    public class UserConfig {
    /**
         * 表示classpath中是否存在某个类的时候就会自动装配,当我们在pom文件中加入了Gson的依赖就自定装配了此对象(实例名为createGsonRunnable)
         * @return
         */
        @Bean
        @ConditionalOnClass(name="com.google.gson.Gson")
        public Runnable createGsonRunnable(){
            return () -> {};
        }
    
    }
    

    当pom文件中加入依赖:

     <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>2.8.1</version>
    </dependency>
    

    启动Application类,控制台打印:

    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
           
            System.out.println(context.getBeansOfType(Runnable.class));
            context.close();
        }
    }
    
    {createGsonRunnable=com.zhihao.miao.config.UserConfig$$Lambda$8/121167003@491b9b8}
    

    ConditionalOnBean

    定义一普通类UserConfig

    @SpringBootConfiguration
    public class UserConfig {
        /**
         * 当spring容器中有user对象的时候,自动装配对象为createBeanRunnable的Runnable实例
         */
        @Bean
        @ConditionalOnBean(name = "user")
        public Runnable createBeanRunnable(){
            return () -> {};
        }
    }
    

    定义一User类,并纳入到spring容器中管理

    @Component("user")
    public class User {
    
        private String username;
    
        private String password;
    }
    

    启动Application类,控制台打印:

    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
           
            System.out.println(context.getBeansOfType(Runnable.class));
            context.close();
        }
    }
    
    createBeanRunnable=com.zhihao.miao.config.UserConfig$$Lambda$9/1014486152@1a4927d6
    

    其实熟悉使用springboot框架的开发者就会知道,官网或者开源组织提供的各种starter依赖(在pom文件加入依赖),然后在配置文件中配置一些属性,比如如果我们使用mongodb的时候,会自动装配一些类来使得我们连接mongodb服务,我们只需要配置一些mongodb的一些服务信息,,而不需要以前在配置文件中进行spring和mongodb的整合

    org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration大量使用官方提供的这些@Conditional**注解,下面截取一段说明一下。

        @Bean
        @ConditionalOnMissingBean(MongoDbFactory.class)
        public SimpleMongoDbFactory mongoDbFactory(MongoClient mongo) throws Exception {
            String database = this.properties.getMongoClientDatabase();
            return new SimpleMongoDbFactory(mongo, database);
        }
    
        @Bean
        @ConditionalOnMissingBean
        public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory,
                MongoConverter converter) throws UnknownHostException {
            return new MongoTemplate(mongoDbFactory, converter);
        }
    
        @Bean
        @ConditionalOnMissingBean(MongoConverter.class)
        public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory,
                MongoMappingContext context, BeanFactory beanFactory,
                CustomConversions conversions) {
            DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
            MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver,
                    context);
            mappingConverter.setCustomConversions(conversions);
            return mappingConverter;
        }
    

    关于自动装配下面的博客会大量使用到此种特性,这也是springboot配置少的根本原因。

    相关文章

      网友评论

        本文标题:Springboot的自动装配

        本文链接:https://www.haomeiwen.com/subject/myotkxtx.html