• SpringBoot自动注入分析


      我们经常会被问到这么一个问题:SpringBoot相对于spring有哪些优势呢?其中有一条答案就是SpringBoot自动注入。那么自动注入的原理是什么呢?我们进行如下分析。

      1:首先我们分析项目的启动类时,发现都会加上@SpringBootApplication这个注解,我们分析这个继续进入这个注解会发现,它是由多个注解组成的,如下

     1 @Target(ElementType.TYPE)
     2 @Retention(RetentionPolicy.RUNTIME)
     3 @Documented
     4 @Inherited
     5 @SpringBootConfiguration
     6 @EnableAutoConfiguration
     7 @ComponentScan(excludeFilters = {
     8         @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
     9         @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    10 public @interface SpringBootApplication {
    View Code

      2:服务启动会扫描 org.springframework.boot.autoconfigure下的 META-INF/spring.factories 这个文件,这个文件中保存着springboot 启动时默认会自动注入的类,部分如下

     1 # Auto Configure
     2 org.springframework.boot.autoconfigure.EnableAutoConfiguration=
     3 org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
     4 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
     5 org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
     6 org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
     7 org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
     8 org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
     9 org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,
    10 org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,
    11 org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,
    12 org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,
    13 org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,
    14 org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,
    15 org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,
    16 org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,
    17 org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,
    18 org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,
    19 org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,
    20 org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,
    21 org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,
    22 org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,
    23 org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,
    24 org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,
    25 org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,
    26 org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,
    27 org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,
    28 org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,
    29 org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,
    30 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,
    31 org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,
    32 org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,
    33 org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,
    34 org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,
    35 org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,
    36 org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,
    37 org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,
    38 org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,
    39 org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,
    40 org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,
    41 org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,
    42 org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,
    43 org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,
    44 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,
    45 org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,
    46 org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,
    47 org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,
    48 org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,
    49 org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,
    50 org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,
    51 org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,
    52 org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,
    53 org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,
    54 org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,
    55 org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,
    56 org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,
    57 org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,
    58 org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,
    59 org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,
    60 org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,
    61 org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,
    62 org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,
    63 org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,
    64 org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,
    65 org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,
    66 org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,
    67 org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,
    68 org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,
    69 org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,
    70 org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,
    71 org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,
    72 org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,
    73 org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,
    74 org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,
    75 org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,
    76 org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,
    77 org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,
    78 org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,
    79 org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,
    80 org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,
    81 org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,
    82 org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,
    83 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,
    84 org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,
    85 org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,
    86 org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,
    87 org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,
    88 org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,
    89 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,
    90 org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,
    91 org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,
    92 org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,
    93 org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,
    94 org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,
    95 org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,
    96 org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,
    97 org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,
    98 org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
    View Code

      3:你是不是在其中发现了自己常用的redis,mysql等相关的类?没错,springboot会尝试加载这些类,我们以 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration 这个类为例,进去看一下它的源码,部分示例如下

     1 @Configuration
     2 @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
     3 @EnableConfigurationProperties(RedisProperties.class)
     4 public class RedisAutoConfiguration {
     5 
     6     /**
     7      * Redis connection configuration.
     8      */
     9     @Configuration
    10     @ConditionalOnClass(GenericObjectPool.class)
    11     protected static class RedisConnectionConfiguration {
    12 
    13         private final RedisProperties properties;
    14 
    15         private final RedisSentinelConfiguration sentinelConfiguration;
    16 
    17         private final RedisClusterConfiguration clusterConfiguration;
    18 
    19         public RedisConnectionConfiguration(RedisProperties properties,
    20                 ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
    21                 ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
    22             this.properties = properties;
    23             this.sentinelConfiguration = sentinelConfiguration.getIfAvailable();
    24             this.clusterConfiguration = clusterConfiguration.getIfAvailable();
    25         }
    26 
    27         @Bean
    28         @ConditionalOnMissingBean(RedisConnectionFactory.class)
    29         public JedisConnectionFactory redisConnectionFactory()
    30                 throws UnknownHostException {
    31             return applyProperties(createJedisConnectionFactory());
    32         }
    View Code

      我们能看到这个类上加了这个注解 @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class }) 意思就是如果你的classpath中没有这些类的话,那么这个类就不能被加载,那么这些被依赖的类在哪出现呢?没错,就在我们在pom.xml中引入的依赖所对应的包里。

      看到这里你因该就明白了,META-INF/spring.factories 文件中被列出来的那些类都会被springboot去尝试加载,但是有些模块我们没引入相关的依赖,那么这个类就会加载失败。即这个模块没有被成功加载。

      4:我们通过上面的redis的自动加载类时,看到上面还有个 @EnableConfigurationProperties(RedisProperties.class) 注解,这个注解来注入关于redis的配置信息,这个信息都在 RedisProperties.class 中保存,我们看下 RedisProperties的源码

      1 @ConfigurationProperties(prefix = "spring.redis")
      2 public class RedisProperties {
      3 
      4     /**
      5      * Database index used by the connection factory.
      6      */
      7     private int database = 0;
      8 
      9     /**
     10      * Redis url, which will overrule host, port and password if set.
     11      */
     12     private String url;
     13 
     14     /**
     15      * Redis server host.
     16      */
     17     private String host = "localhost";
     18 
     19     /**
     20      * Login password of the redis server.
     21      */
     22     private String password;
     23 
     24     /**
     25      * Redis server port.
     26      */
     27     private int port = 6379;
     28 
     29     /**
     30      * Enable SSL.
     31      */
     32     private boolean ssl;
     33 
     34     /**
     35      * Connection timeout in milliseconds.
     36      */
     37     private int timeout;
     38 
     39     private Pool pool;
     40 
     41     private Sentinel sentinel;
     42 
     43     private Cluster cluster;
     44 
     45     public int getDatabase() {
     46         return this.database;
     47     }
     48 
     49     public void setDatabase(int database) {
     50         this.database = database;
     51     }
     52 
     53     public String getUrl() {
     54         return this.url;
     55     }
     56 
     57     public void setUrl(String url) {
     58         this.url = url;
     59     }
     60 
     61     public String getHost() {
     62         return this.host;
     63     }
     64 
     65     public void setHost(String host) {
     66         this.host = host;
     67     }
     68 
     69     public String getPassword() {
     70         return this.password;
     71     }
     72 
     73     public void setPassword(String password) {
     74         this.password = password;
     75     }
     76 
     77     public int getPort() {
     78         return this.port;
     79     }
     80 
     81     public void setPort(int port) {
     82         this.port = port;
     83     }
     84 
     85     public boolean isSsl() {
     86         return this.ssl;
     87     }
     88 
     89     public void setSsl(boolean ssl) {
     90         this.ssl = ssl;
     91     }
     92 
     93     public void setTimeout(int timeout) {
     94         this.timeout = timeout;
     95     }
     96 
     97     public int getTimeout() {
     98         return this.timeout;
     99     }
    100 
    101     public Sentinel getSentinel() {
    102         return this.sentinel;
    103     }
    104 
    105     public void setSentinel(Sentinel sentinel) {
    106         this.sentinel = sentinel;
    107     }
    108 
    109     public Pool getPool() {
    110         return this.pool;
    111     }
    112 
    113     public void setPool(Pool pool) {
    114         this.pool = pool;
    115     }
    116 
    117     public Cluster getCluster() {
    118         return this.cluster;
    119     }
    120 
    121     public void setCluster(Cluster cluster) {
    122         this.cluster = cluster;
    123     }
    124 
    125     /**
    126      * Pool properties.
    127      */
    128     public static class Pool {
    129 
    130         /**
    131          * Max number of "idle" connections in the pool. Use a negative value to indicate
    132          * an unlimited number of idle connections.
    133          */
    134         private int maxIdle = 8;
    135 
    136         /**
    137          * Target for the minimum number of idle connections to maintain in the pool. This
    138          * setting only has an effect if it is positive.
    139          */
    140         private int minIdle = 0;
    141 
    142         /**
    143          * Max number of connections that can be allocated by the pool at a given time.
    144          * Use a negative value for no limit.
    145          */
    146         private int maxActive = 8;
    147 
    148         /**
    149          * Maximum amount of time (in milliseconds) a connection allocation should block
    150          * before throwing an exception when the pool is exhausted. Use a negative value
    151          * to block indefinitely.
    152          */
    153         private int maxWait = -1;
    154 
    155         public int getMaxIdle() {
    156             return this.maxIdle;
    157         }
    158 
    159         public void setMaxIdle(int maxIdle) {
    160             this.maxIdle = maxIdle;
    161         }
    162 
    163         public int getMinIdle() {
    164             return this.minIdle;
    165         }
    166 
    167         public void setMinIdle(int minIdle) {
    168             this.minIdle = minIdle;
    169         }
    170 
    171         public int getMaxActive() {
    172             return this.maxActive;
    173         }
    174 
    175         public void setMaxActive(int maxActive) {
    176             this.maxActive = maxActive;
    177         }
    178 
    179         public int getMaxWait() {
    180             return this.maxWait;
    181         }
    182 
    183         public void setMaxWait(int maxWait) {
    184             this.maxWait = maxWait;
    185         }
    186 
    187     }
    188 
    189     /**
    190      * Cluster properties.
    191      */
    192     public static class Cluster {
    193 
    194         /**
    195          * Comma-separated list of "host:port" pairs to bootstrap from. This represents an
    196          * "initial" list of cluster nodes and is required to have at least one entry.
    197          */
    198         private List<String> nodes;
    199 
    200         /**
    201          * Maximum number of redirects to follow when executing commands across the
    202          * cluster.
    203          */
    204         private Integer maxRedirects;
    205 
    206         public List<String> getNodes() {
    207             return this.nodes;
    208         }
    209 
    210         public void setNodes(List<String> nodes) {
    211             this.nodes = nodes;
    212         }
    213 
    214         public Integer getMaxRedirects() {
    215             return this.maxRedirects;
    216         }
    217 
    218         public void setMaxRedirects(Integer maxRedirects) {
    219             this.maxRedirects = maxRedirects;
    220         }
    221 
    222     }
    223 
    224     /**
    225      * Redis sentinel properties.
    226      */
    227     public static class Sentinel {
    228 
    229         /**
    230          * Name of Redis server.
    231          */
    232         private String master;
    233 
    234         /**
    235          * Comma-separated list of host:port pairs.
    236          */
    237         private String nodes;
    238 
    239         public String getMaster() {
    240             return this.master;
    241         }
    242 
    243         public void setMaster(String master) {
    244             this.master = master;
    245         }
    246 
    247         public String getNodes() {
    248             return this.nodes;
    249         }
    250 
    251         public void setNodes(String nodes) {
    252             this.nodes = nodes;
    253         }
    254 
    255     }
    256 
    257 }
    View Code

      发现里面的配置项基本都是有默认值的,通过上面的注解可以明白,如果配置文件中存在 spring.redis 开头的配置项,则使用配置文件中的,如果没有的话则使用文件中默认写死的配置。你是不是想到了springboot的另外一个优势:约定大于配置。

      这里我们大概了解了SpringBoot自动配置的原理和流程,里面的那些细节我们不在分析。同理,对于那些第三方或者我们自己写的starter,springboot启动的时候会扫描starter的jar包下 META-INF/spring.factories 这个文件,解析内容并加载里面对用的类。

      由此,我们总结出以下几点

      1:SpringBoot的自动配置是如何实现的

      2:有关的那些注解,如@EnableAutoConfiguration, @ConditionalOnClass, @Configuration等也是SpringBoot的核心注解,也值得我们了解其用法和原理。

     

  • 相关阅读:
    epoll示例
    realloc的使用误区
    pyCharm最新激活码(2018激活码)
    python程序打包成.exe
    VS2017下载安装
    C# Cache缓存读取设置
    WPF中展示HTML
    Aspose Word模板使用总结
    js alert(“”)弹框 自定义样式
    利用反射将Model转化为sql
  • 原文地址:https://www.cnblogs.com/wanghaoyang/p/11693973.html
Copyright © 2020-2023  润新知