spring-boot系列

spring-boot系列



前言

本节主要讲Condition接口、切换内置服务器、@Enable*注解、@SpringBootApplication四个部分


在这里插入图片描述


一、Condition接口

1. 来历

Condition接口,是在spring4.0增加的条件判断功能,可以实现选择性的创建bean操作

2. 使用方法

@Conditional(ClassCondition.class),这个注解需要传递一个实现了Condition接口的class对象,
Condition接口只有一个boolean matches()方法,用此条件来判断这个bean是否创建

自定义注解@ConditionOnClass:
    首先要继承@Conditional(ClassCondition.class),表明此注解是个衍生注解,
    功能和@Conditional()完全一样,但是可以自己定义一个String[] value();
    当其它类使用这个注解时,能够传入String数组,交给自定义的OnClassCondition类
    使用,具体写法如下:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionOnClass {
    String[] value();
}
自定义OnClassCondition:
	metadata.getAnnotationAttributes(String annotationName).get("value")
		方法能获取注解的value数组,这样可以将前面自定义的注解传入并获取
	再将每个value进行判断来返回相应的布尔值,就可以实现不同条件是否创建bean
本例是通过Class.forName(className);来判断传入的类是否存在,存在就返回true
public class OnClassCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
        String[] classNames = (String[]) metadata.getAnnotationAttributes(ConditionOnClass.class.getName()).get("value");
        for (String className : classNames) {
            try {
                Class.forName(className);
            } catch (ClassNotFoundException e) {
                return false;
            }
        }
        return true;
    }
}
    //至此,实现了必须存在这个对象才能创建这个bean
    @ConditionOnClass("org.springframework.data.redis.core.RedisTemplate")
    @Bean
    public RedisTemplate redisTemplate(){
        return new RedisTemplate();
    }
在Maven:org.springframework.boot:spring-boot-autoconfigure中的condition包下,
有一系列的ConditionOn*的注解,就是用来实现各种bean动态创建的,
我们通常可以使用这些注解来决定bean是否创建

二、切换内置服务器

1.服务器切换
切换内置服务器jetty、undertow、netty,通过pom文件配置
在Maven:org.springframework.boot:spring-boot-autoconfigure中的web包下
的embedded包有四个web服务器,修改最后的名字就可以了
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <groupId>org.springframework.boot</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

三、@Enable*注解

1.介绍
@Enable*注解,用于开启某些功能,底层是@import注解,实现bean的动态加载
2.@Import详解
@Import(xxx.class)注解能够将一个类xxx导入spring容器中,通常将其配置spring类上
(例如@Configuration),作为导入bean的一种方式,此外,他还有两种
方式,一是导入实现了ImportSelector接口的类,通过数组导入:
	@Import(MyImportSelector.class)
	
二是导入实现ImportBeanDefinitionRegistrar接口的类,通过bean工厂注册:
	@Import(MyImportBeanDefinitionRegistrar)
以下是实现代码:

	public class MyImportSelector implements ImportSelector {
		@Override
		public String[] selectImports(AnnotationMetadata annotationMetadata) {
			return new String[]{"com.lzb.other.bean.User","com.lzb.other.bean.Address"};
		}
	}
	

	public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
		@Override
		public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
			AbstractBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
			registry.registerBeanDefinition("com.lzb.other.bean.User",definition);
		}
	}

@Import()注解底层应该有某种方法,使得一执行这个注解,就会将bean加入到容器中
3.自定义@Enable*类型注解
由于@Import()的功能,我们知道只要引入了这个注解就相当于定义了引入的bean,所以我们只
需要写一个衍生注解就可以实现功能:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import(User.class)
public @interface EnableUser {
}

@EnableUser配合getbean或者@Autowired就可以注入

四、@SpringBootApplication

1. @SpringBootApplication启动注解
    @SpringBootApplication包括:
		@SpringBootConfiguration
		@EnableAutoConfiguration
		@ComponontScan
2. @SpringBootConfiguration
@Configuration衍生注解,和spring-boot配套使用
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
3.@EnableAutoConfiguration
它是通过@Import导入了AutoConfigurationImportSelector.class,这个类是通过
父类实现了ImportSelector接口,并重写了selectImports()方法,来实现bean注入
AutoConfigurationImportSelector类有一个getCandidateConfigurations()方法,
这个方法就是用来加载META-INF/spring.factories配置文件,返回可以加载的配置类名的
字符串集合,这些字符串就是可加载的类名,进入spring.factories可以发现,他加载了许
多类名,但并不是所有的类都会被加载,因为每一个类都有一个@ConditionOn*注解,大多数
是@ConditionOnClass(*.class)这个注解用来判定是否加载该类。
这个文件十分重要,因为只要启动spring-boot项目,这个文件就会被加载并导入可加载的bean
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
4.@EnableConfigurationProperties(Redis.properties)
原理就是@Enable*,它能够将配置了@ConfigurationProperties(prefix = "redis")
的属性文件类导入到容器中,并且优先使用application.yml设置的值
5.自定义starter
这是属性配置类,用来和接收application.yml设置的值,好传递给其它需要的类
package com.lzb.redis.configure;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "redis")
public class RedisProperties {
    private String host = "localhost";
    private int port = 6379;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }
}
这是提供bean的类,通过@EnableConfigurationProperties(RedisProperties.class)
注入配置文件的值,来实现参数的动态化
package com.lzb.redis.configure;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;

@EnableConfigurationProperties(RedisProperties.class)
@Configuration
@ConditionalOnClass(Jedis.class)
public class RedisConfiguration {
    /**
     * 提供jedis的bean
     */
    @Bean
    @ConditionalOnMissingBean(name = "jedis")
    public Jedis jedis(RedisProperties redisProperties){
        return new Jedis(redisProperties.getHost(),redisProperties.getPort());
    }
}
这是配置文件resources/META-INF/spring.factories 
它是随着@EnableAutoConfiguration启动注解加载的,它会先找到这个类,然后对它进行
实例化bean的操作,如果满足@ConditionalOnClass(Jedis.class)和
@ConditionalOnMissingBean(name = "jedis"),就会将这个bean加入到容器中,否则
不创建这个bean                    ↓
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.lzb.redis.configure.RedisConfiguration
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值