SpringBoot:快速入门

来自Wikioe
跳到导航 跳到搜索


Spring的发展

  1. Spring1.x:
    通过xml文件配置bean:随着项目的不断扩大,需要将xml配置分放到不同的配置文件中,需要频繁的在java类和xml配置文件中切换。
  2. Spring2.x:
    (JDK 1.5 注解支持)使用注解对Bean进行申明和注入:大大的减少了xml配置文件,同时也大大简化了项目的开发。
    1. 应用的基本配置用xml(如:数据源、资源文件等);
    2. 业务开发用注解(如:Service中注入bean等);
  3. Spring3.x(Spring4.x):
    推荐使用Java配置方式:可以完全替代xml配置。

Spring的Java配置方式

(Java配置是Spring4.x推荐的配置方式)
Spring的Java配置方式是通过 @Configuration 和 @Bean 这两个注解实现的:

  1. @Configuration:标记类,相当于一个xml配置文件;
  2. @Bean:标记方法,相当于xml配置中的“<bean>”;


其他配置类注解:

  1. 读取外部的资源配置文件:
    1. @PropertySource:指定读取的配置文件;
    2. @Value:获取配置文件的配置项;


示例:配置数据库连接池:

// 通过该注解来表明该类是一个Spring的配置,相当于一个xml文件
@Configuration
// 配置扫描包,相当于xml中的"<context:component-scan ...>"
@ComponentScan(basePackages = "cn.itcast.springboot.javaconfig")
//加载配置文件
@PropertySource(value = { "classpath:jdbc.properties", "xxx.properties" }, ignoreResourceNotFound = true)
public class SpringConfig {

    @Bean
    // 通过该注解来表明是一个Bean对象,相当于xml中的<bean>
    //1、相当于xml中的<bean>标签
    //2、相当于类中的@Service类的注解
    //所以"UserDAO"可以用于"UserService"属性注入
    public UserDAO getUserDAO() {
        return new UserDAO(); // 直接new对象做演示
    }
    //返回值,相当于<bean>中的"class"属性
    //方法名称,相当于<bean>中的"id"属性?
    
    // 获取配置文件的配置项
    @Value("${jdbc.url}")
    private String jdbcUrl;

    @Value("${jdbc.driverClassName}")
    private String jdbcDriverClassName;

    @Value("${jdbc.username}")
    private String jdbcUsername;

    @Value("${jdbc.password}")
    private String jdbcPassword;

    @Bean(destroyMethod = "close")
    public DataSource dataSource() {
        BoneCPDataSource boneCPDataSource = new BoneCPDataSource();
        // 数据库驱动
        boneCPDataSource.setDriverClass(jdbcDriverClassName);
        // 相应驱动的jdbcUrl
        boneCPDataSource.setJdbcUrl(jdbcUrl);
        // 数据库的用户名
        boneCPDataSource.setUsername(jdbcUsername);
        // 数据库的密码
        boneCPDataSource.setPassword(jdbcUsername);
        // 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0
        boneCPDataSource.setIdleConnectionTestPeriodInMinutes(60);
        // 连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0
        boneCPDataSource.setIdleMaxAgeInMinutes(30);
        // 每个分区最大的连接数
        boneCPDataSource.setMaxConnectionsPerPartition(100);
        // 每个分区最小的连接数
        boneCPDataSource.setMinConnectionsPerPartition(5);
        return boneCPDataSource;
    }
}

实例

  1. 创建工程以及导入依赖:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>cn.itcast.springboot</groupId>
    	<artifactId>itcast-springboot</artifactId>
    	<version>1.0.0-SNAPSHOT</version>
    	<packaging>war</packaging>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-webmvc</artifactId>
    			<version>4.3.7.RELEASE</version>
    		</dependency>
            
    		<!-- 连接池 -->
    		<dependency>
    			<groupId>com.jolbox</groupId>
    			<artifactId>bonecp-spring</artifactId>
    			<version>0.8.0.RELEASE</version>
    		</dependency>
    	</dependencies>
        
    	<build>
    		<finalName>${project.artifactId}</finalName>
    		<plugins>
    			<!-- 资源文件拷贝插件 -->
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-resources-plugin</artifactId>
    				<configuration>
    					<encoding>UTF-8</encoding>
    				</configuration>
    			</plugin>
                
    			<!-- java编译插件 -->
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-compiler-plugin</artifactId>
    				<configuration>
    					<source>1.7</source>
    					<target>1.7</target>
    					<encoding>UTF-8</encoding>
    				</configuration>
    			</plugin>
    		</plugins>
            
    		<pluginManagement>
    			<plugins>
    				<!-- 配置Tomcat插件 -->
    				<plugin>
    					<groupId>org.apache.tomcat.maven</groupId>
    					<artifactId>tomcat7-maven-plugin</artifactId>
    					<version>2.2</version>
    				</plugin>
    			</plugins>
    		</pluginManagement>
    	</build>
    </project>
    
  2. 编写User对象:
    public class User {
    
        private String username;
        private String password;
        private Integer age;
    
        // getter & setter & toString
    }
    
  3. 编写UserDao接口:
    public interface UserDao {
        //根据id查询用户信息
    	public User findUserById(int id) throws Exception;
    }
    
  4. 编写UserDaoImpl接口:(mybatis)
    public class UserDaoImpl implements UserDao {
    	// 需要向dao实现类中注入SqlSessionFactory
    	// 这里通过构造方法注入
    	private SqlSessionFactory sqlSessionFactory;
    
    	public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
    		this.sqlSessionFactory = sqlSessionFactory;
    	}
    
    	@Override
    	public User findUserById(int id) throws Exception {
    		SqlSession sqlSession = sqlSessionFactory.openSession();
    
    		User user = sqlSession.selectOne("test.findUserById", id);
    		// 释放资源
    		sqlSession.close();
            
    		return user;
    	}
    }
    
  5. 编写UserService实现User数据操作业务逻辑:
    @Service
    public class UserService {
        @Autowired // 注入Spring容器中的bean对象
        private UserDaoImpl UserDaoImpl;
    
        public User findUserById(int id) throws Exception {
            // 调用userDAO中的方法进行查询
            return this.UserDaoImpl.findUserById(id);
        }
    }
    
  6. 编写SpringConfig用于实例化Spring容器
    @Configuration //通过该注解来表明该类是一个Spring的配置,相当于一个xml文件
    @ComponentScan(basePackages = "cn.itcast.springboot.javaconfig") //配置扫描包
    public class SpringConfig {
        @Bean // 通过该注解来表明是一个Bean对象,相当于xml中的<bean>
        public UserDao getUserDao(){
            return new UserDao(); // 直接new对象做演示
        }
    }
    
  7. 编写测试方法,启动Spring容器
    public class Main {
        public static void main(String[] args) {
            // 使用xml方式的“加载spring配置文件”
            ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    		// 对比使用:通过Java配置来实例化Spring容器
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
            
            // 使用xml方式的“根据配置创建对象”
            UserService userService = (UserService) context.getBean("userService");
            // 对比使用:在Spring容器中获取Bean对象
            UserService userService = context.getBean(UserService.class);
            
            // 调用对象中的方法
            List<User> list = userService.queryUserList();
            for (User user : list) {
                System.out.println(user.getUsername() + ", " + user.getPassword() + ", " + user.getPassword());
            }
            
            // 销毁该容器
            context.destroy();
        }
    }
    

实例化Spring容器:xml与Java配置

对比,“xml、注解”于“Java配置类”的实例化Spring容器:

    // 通过Java配置来实例化Spring容器
    // 1、Java配置类
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    // 2、xml、注解
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
    // 在Spring容器中“获取Bean对象”
    // 1、Java配置类
    UserService userService = context.getBean(UserService.class);
    // 2、xml、注解
    UserService userService = (UserService) context.getBean("userService");

Spring Boot

“习惯优于配置”:

SpringBoot是一种全新的框架,目的是为了简化Spring应用的初始搭建以及开发过程。该框架使用特定的方式(集成starter,约定优于配置)来进行配置,从而使开发人员不需要再定义样板化的配置。

  • SpringBoot基于Sring4进行设计,继承了原有Spring框架的优秀基因。
  • SpringBoot并不是一个框架,而是一些类库的集合。
  • maven或者gradle项目导入相应依赖即可使用SpringBoot,而无需自行管理这些类库的版本。

优点:

  1. 快速创建基于Spring的应用程序。
  2. 无需手动管理依赖包的版本。
  3. 自动配置,无需XML。
  4. 嵌入式的Tomcat,无需部署war文件。

快速入门

设置spring boot的parent

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.2.RELEASE</version>
	</parent>

Spring boot的项目必须要将parent设置为spring boot的parent,该parent包含了大量默认的配置,大大简化了我们的开发。

导入spring boot的web支持

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>

添加Spring boot的插件

	<build>
		<finalName>${project.artifactId}</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
		<pluginManagement>
				...
		</pluginManagement>
	</build>

编写第一个Spring Boot的应用

@Controller
@SpringBootApplication
@Configuration
public class HelloApplication {
    
    @RequestMapping("hello")
    @ResponseBody
    public String hello(){
        return "hello world!";
    }
    
    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class, args);
    }
}
  1. @SpringBootApplication:Spring Boot项目的核心注解,主要目的是开启自动配置;
  2. @Configuration:这是一个配置Spring的配置类;
  3. @Controller:标明这是一个SpringMVC的Controller控制器;
  4. main方法:在main方法中启动一个应用,即:这个应用的入口;

启动应用

在Spring Boot项目中,启动的方式有两种,一种是另外一种是。

  1. 直接run Java Application
    SpringBoot启动应用:RunAS ”Java Aplication“.png
  2. 通过Spring Boot的Maven插件运行
    SpringBoot启动应用:Maven插件运行.png

SpringBoot核心

入口类和@SpringBootApplication

Spring Boot的项目一般都会有“xxxApplication”的入口类,类中有main方法,这是一个标准的Java应用程序的入口方法。

@Controller
@SpringBootApplication(exclude = { RedisAutoConfiguration.class })
@Configuration
public class HelloApplication {

    public static void main(String[] args) {
         SpringApplication.run(HelloApplication.class, args);
    }
}

其中:“@SpringBootApplication”:是Spring Boot的核心注解,它其实是一个组合注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
  1. @SpringBootConfiguration”:Spring Boot项目的配置注解(组合注解):
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    public @interface SpringBootConfiguration {
    }
    
    • 在Spring Boot中推荐使用“@SpringBootConfiguration”替代“@Configuration”;
  2. @EnableAutoConfiguration”:启用自动配置,该注解会使Spring Boot根据项目中依赖的jar包自动配置项目的配置项:
  3. @ComponentScan”:默认扫描“@SpringBootApplication”所在类的同级目录,以及它的子目录;

关闭自动配置

启用自动配置时,Spring Boot会根据项目中的jar包依赖,自动做出配置;而Spring Boot支持的自动配置如下(非常多):

SpringBoot启动应用:自动配置.png

如果不需要Spring Boot自动配置,想关闭某一项的自动配置(以Redis为例):

@Controller
@SpringBootApplication(exclude = { RedisAutoConfiguration.class })
@Configuration
public class HelloApplication {

自定义Banner

启动Spring Boot项目后会看到默认的Banner:

SpringBoot启动应用:Banner.png
  • 关闭Banner:
        public static void main(String[] args) {
    //        SpringApplication.run(HelloApplication.class, args);
    
             SpringApplication application = new SpringApplication(HelloApplication.class);
             application.setBannerMode(Mode.OFF);
             application.run(args);
        }
    
  • 自定义Banner:
    1. 工具站点中生成Banner,并保存为“banner.txt”;
    2. 将banner.txt拷贝到项目的resources目录;
      SpringBoot启动应用:Banner自定义.png

全局配置文件

Spring Boot项目使用一个全局的配置文件“application.properties”(或“application.yml”),在“resources”目录下(或:类路径下的“/config”下)。
可以进行项目全局配置,如:

server.port=8088
server.servlet-path=/

spring.resources.static-locations=classpath:/public/

logging.level.org.springframework=DEBUG

Starter pom

Starter POMs是可以包含到应用中的一个方便的“依赖关系描述符集合”。

  • 可以通过starters获取所有Spring及相关技术的一站式服务,而不需要翻阅示例代码,拷贝粘贴大量的依赖描述符;
  • 所有的starters遵循一个相似的命名模式:“spring-boot-starter-*”;

例如:在 SpringBoot 项目中集成 Redis,那么我只需要加入“spring-data-redis-starter”的依赖:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

而不需考虑与其他内容的依赖、版本等;


官方支持的 starter pom:(2.3.5.RELEASE)

名称 描述
application starters
spring-boot-starter Core starter, including auto-configuration support, logging and YAML
spring-boot-starter-activemq Starter for JMS messaging using Apache ActiveMQ
spring-boot-starter-amqp Starter for using Spring AMQP and Rabbit MQ
spring-boot-starter-aop Starter for aspect-oriented programming with Spring AOP and AspectJ
spring-boot-starter-artemis Starter for JMS messaging using Apache Artemis
spring-boot-starter-batch Starter for using Spring Batch
spring-boot-starter-cache Starter for using Spring Framework’s caching support
spring-boot-starter-data-cassandra Starter for using Cassandra distributed database and Spring Data Cassandra
spring-boot-starter-data-cassandra-reactive Starter for using Cassandra distributed database and Spring Data Cassandra Reactive
spring-boot-starter-data-couchbase Starter for using Couchbase document-oriented database and Spring Data Couchbase
spring-boot-starter-data-couchbase-reactive Starter for using Couchbase document-oriented database and Spring Data Couchbase Reactive
spring-boot-starter-data-elasticsearch Starter for using Elasticsearch search and analytics engine and Spring Data Elasticsearch
spring-boot-starter-data-jdbc Starter for using Spring Data JDBC
spring-boot-starter-data-jpa Starter for using Spring Data JPA with Hibernate
spring-boot-starter-data-ldap Starter for using Spring Data LDAP
spring-boot-starter-data-mongodb Starter for using MongoDB document-oriented database and Spring Data MongoDB
spring-boot-starter-data-mongodb-reactive Starter for using MongoDB document-oriented database and Spring Data MongoDB Reactive
spring-boot-starter-data-neo4j Starter for using Neo4j graph database and Spring Data Neo4j
spring-boot-starter-data-r2dbc Starter for using Spring Data R2DBC
spring-boot-starter-data-redis Starter for using Redis key-value data store with Spring Data Redis and the Lettuce client
spring-boot-starter-data-redis-reactive Starter for using Redis key-value data store with Spring Data Redis reactive and the Lettuce client
spring-boot-starter-data-rest Starter for exposing Spring Data repositories over REST using Spring Data REST
spring-boot-starter-data-solr Starter for using the Apache Solr search platform with Spring Data Solr
spring-boot-starter-freemarker Starter for building MVC web applications using FreeMarker views
spring-boot-starter-groovy-templates Starter for building MVC web applications using Groovy Templates views
spring-boot-starter-hateoas Starter for building hypermedia-based RESTful web application with Spring MVC and Spring HATEOAS
spring-boot-starter-integration Starter for using Spring Integration
spring-boot-starter-jdbc Starter for using JDBC with the HikariCP connection pool
spring-boot-starter-jersey Starter for building RESTful web applications using JAX-RS and Jersey. An alternative to spring-boot-starter-web
spring-boot-starter-jooq Starter for using jOOQ to access SQL databases. An alternative to spring-boot-starter-data-jpa or spring-boot-starter-jdbc
spring-boot-starter-json Starter for reading and writing json
spring-boot-starter-jta-atomikos Starter for JTA transactions using Atomikos
spring-boot-starter-jta-bitronix Starter for JTA transactions using Bitronix. Deprecated since 2.3.0
spring-boot-starter-mail Starter for using Java Mail and Spring Framework’s email sending support
spring-boot-starter-mustache Starter for building web applications using Mustache views
spring-boot-starter-oauth2-client Starter for using Spring Security’s OAuth2/OpenID Connect client features
spring-boot-starter-oauth2-resource-server Starter for using Spring Security’s OAuth2 resource server features
spring-boot-starter-quartz Starter for using the Quartz scheduler
spring-boot-starter-rsocket Starter for building RSocket clients and servers
spring-boot-starter-security Starter for using Spring Security
spring-boot-starter-test Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito
spring-boot-starter-thymeleaf Starter for building MVC web applications using Thymeleaf views
spring-boot-starter-validation Starter for using Java Bean Validation with Hibernate Validator
spring-boot-starter-web Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container
spring-boot-starter-web-services Starter for using Spring Web Services
spring-boot-starter-webflux Starter for building WebFlux applications using Spring Framework’s Reactive Web support
spring-boot-starter-websocket Starter for building WebSocket applications using Spring Framework’s WebSocket support
production starters
spring-boot-starter-actuator Starter for using Spring Boot’s Actuator which provides production ready features to help you monitor and manage your application
technical starters
spring-boot-starter-jetty Starter for using Jetty as the embedded servlet container. An alternative to spring-boot-starter-tomcat
spring-boot-starter-log4j2 Starter for using Log4j2 for logging. An alternative to spring-boot-starter-logging
spring-boot-starter-logging Starter for logging using Logback. Default logging starter
spring-boot-starter-reactor-netty Starter for using Reactor Netty as the embedded reactive HTTP server.
spring-boot-starter-tomcat Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web
spring-boot-starter-undertow Starter for using Undertow as the embedded servlet container. An alternative to spring-boot-starter-tomcat

Xml 配置文件

  1. @PropertySource”:加载指定的配置文件;
    • 只能加载“*.properties”文件,不能加载“.yaml”文件;
    @PropertySource(value = { "classpath:jdbc.properties" }, ignoreResourceNotFound = true)
    
  2. @Import”:
    • 4.2之前,只支持导入配置类;(相当于“<import resource=""/>”标签)
    • 4.2之后,支持导入普通的java类,并将其声明成一个bean;
    @Import({ CustomerConfig.class, SchedulerConfig.class })
    
  3. @ImportResource”:导入Spring的配置文件,让配置文件里面的内容生效;
    • SpringBoot中编写的Spring配置文件是不能自动识别的;【???】
    @ImportResource(locations = {"classpath:applicationContext.xml"})
    

日志

Spring Boot对各种日志框架都做了支持,可以通过全局配置来修改默认的日志的配置:

#设置日志级别
logging.level.*= # Log levels severity mapping. For instance `logging.level.org.springframework=DEBUG`

自动配置的原理

Spring Boot在进行SpringApplication对象实例化时会加载“META-INF/spring.factories”文件,将该配置文件中的配置载入到Spring容器。

  • “META-INF/spring.factories”文件,位于“spring-boot-autoconfigure-1.5.2.RELEASE.jar”包中,而非项目路径下;
    Spring-boot-autoconfigure-1.5.2.RELEASE包中.jpg
  • 全局配置“application.properties”(“application.yml”)时,需要的配置项,可以根据jar包(“org.springframework.boot.autoconfigure”)下对应包中的自动配置类得出;
    如下面的 Redis的自动配置;

spring.factories 的加载

配置文件“spring.factories”的读取,是在“org.springframework.boot.SpringApplication”的初始化方法中进行的:

public class SpringApplication {
   ...
   @SuppressWarnings({ "unchecked", "rawtypes" })
	private void initialize(Object[] sources) {
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
		this.webEnvironment = deduceWebEnvironment();
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
   ...
   private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}
   private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<String>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
   ...
}

“org.springframework.core.io.support.SpringFactoriesLoader”:

public abstract class SpringFactoriesLoader {
   ...
   public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
   ...
   public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
		String factoryClassName = factoryClass.getName();
		try {
			Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			List<String> result = new ArrayList<String>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
				String factoryClassNames = properties.getProperty(factoryClassName);
				result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
			}
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}
   ...
}

示例:Redis的自动配置

由“spring.factories”文件:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
...
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
...

可知“org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration”是Redis的自动配置:

Spring-boot:RedisAutoConfiguration.jpg
@Configuration
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {

	@Configuration
	@ConditionalOnClass(GenericObjectPool.class)
	protected static class RedisConnectionConfiguration {
		private final RedisProperties properties;
		private final RedisSentinelConfiguration sentinelConfiguration;
		private final RedisClusterConfiguration clusterConfiguration;
      ...
   }
   
   @Configuration
	protected static class RedisConfiguration {
		@Bean
		@ConditionalOnMissingBean(name = "redisTemplate")
		public RedisTemplate<Object, Object> redisTemplate(
				RedisConnectionFactory redisConnectionFactory)
						throws UnknownHostException {
			RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
			template.setConnectionFactory(redisConnectionFactory);
			return template;
		}

		@Bean
		@ConditionalOnMissingBean(StringRedisTemplate.class)
		public StringRedisTemplate stringRedisTemplate(
				RedisConnectionFactory redisConnectionFactory)
						throws UnknownHostException {
			StringRedisTemplate template = new StringRedisTemplate();
			template.setConnectionFactory(redisConnectionFactory);
			return template;
		}
   }
}
  1. 内部类“RedisConnectionConfiguration”:Redis连接设置;
    • “RedisProperties”:Redis配置类;
  2. 内部类“RedisConfiguration”:获取RedisTemplate;


  • “RedisProperties”:
    @ConfigurationProperties(prefix = "spring.redis")
    public class RedisProperties {
    
    	/**
    	 * Database index used by the connection factory.
    	 */
    	private int database = 0;
    
    	/**
    	 * Redis url, which will overrule host, port and password if set.
    	 */
    	private String url;
    
    	/**
    	 * Redis server host.
    	 */
    	private String host = "localhost";
    
    	/**
    	 * Login password of the redis server.
    	 */
    	private String password;
        
        ...
    }
    
    1. “(prefix = "spring.redis")”:配置项的前缀(匹配SpringBoot全局配置文件中的前缀);
    2. “database”、“url”等:配置项;

条件注解

SpringBoot内部提供了特有的注解:条件注解(Conditional Annotation);

条件注解存在的意义在于动态识别(也可以说是代码自动化执行)。比如@ConditionalOnClass会检查类加载器中是否存在对应的类,如果有的话被注解修饰的类就有资格被Spring容器所注册,否则会被skip。


条件注解 对应的Condition处理类 说明
@ConditionalOnBean OnBeanCondition Spring容器中是否存在对应的实例。
  • 可以通过实例的类型、类名、注解、昵称去容器中查找;
  • (可以配置从当前容器中查找或者父容器中查找或者两者一起查找);
  • 这些属性都是数组,通过”与”的关系进行查找;
@ConditionalOnBean(javax.sql.DataSource.class)
// Spring容器或者所有父容器中需要存在至少一个javax.sql.DataSource类的实例
@ConditionalOnClass OnClassCondition 类加载器中是否存在对应的类。
  • 可以通过Class指定(value属性)或者Class的全名指定(name属性);
  • 如果是多个类或者多个类名的话,关系是”与”关系,也就是说这些类或者类名都必须同时在类加载器中存在;
@ConditionalOnClass({ Configuration.class, FreeMarkerConfigurationFactory.class })
// 类加载器中必须存在 Configuration和 FreeMarkerConfigurationFactory这两个类
@ConditionalOnExpression OnExpressionCondition 判断SpEL 表达式是否成立
@ConditionalOnExpression("'${server.host}'=='localhost'")
// server.host配置项的值需要是localhost
@ConditionalOnJava OnJavaCondition 指定Java版本是否符合要求。
  • 内部有2个属性“value”和“range”:
    1. value表示一个枚举的Java版本,
    2. range表示比这个老或者新于等于指定的Java版本(默认是新于等于)。
  • 内部会基于某些jdk版本特有的类去类加载器中查询,比如:
    1. 如果是jdk9,类加载器中需要存在“java.security.cert.URICertStoreParameters”;
    2. 如果是jdk8,类加载器中需要存在“java.util.function.Function”;
    3. 如果是jdk7,类加载器中需要存在“java.nio.file.Files”;
    4. 如果是jdk6,类加载器中需要存在“java.util.ServiceLoader”
ConditionalOnJava(JavaVersion.EIGHT)
// Java版本至少是8
@ConditionalOnMissingBean OnBeanCondition Spring容器中是否缺少对应的实例。
  • 可以通过实例的类型、类名、注解、昵称去容器中查找
    (可以配置从当前容器中查找或者父容器中查找或者两者一起查找)
  • 这些属性都是数组,通过”与”的关系进行查找。
  • 还多了2个属性ignored(类名)和ignoredType(类名),匹配的过程中会忽略这些bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
// Spring当前容器中不存在ErrorController类型的bean
@ConditionalOnMissingClass OnClassCondition 跟ConditionalOnClass的处理逻辑一样,只是条件相反,在类加载器中不存在对应的类
@ConditionalOnMissingClass("GenericObjectPool")
// 类加载器中不能存在GenericObjectPool这个类
@ConditionalOnNotWebApplication OnWebApplicationCondition 应用程序是否是非Web程序,没有提供属性,只是一个标识。
  • 会从判断Web程序特有的类是否存在,环境是否是Servlet环境,容器是否是Web容器等
@ConditionalOnNotWebApplication
// 必须在非Web应用下才会生效
@ConditionalOnProperty OnPropertyCondition 应用环境中的屬性是否存在。
  • 提供“prefix”、“name”、“havingValue”以及“matchIfMissing”属性。
    prefix:属性名的前缀,
    name:属性名,
    havingValue:具体的属性值,
    matchIfMissing:(boolean值)如果属性不存在,这个matchIfMissing为true的话,会继续验证下去,否则属性不存在的话直接就相当于匹配不成功;
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
// 应用程序的环境中必须有spring.aop.auto这项配置,且它的值是true或者环境中不存在spring.aop.auto配置(matchIfMissing为true)
@ConditionalOnResource OnResourceCondition 是否存在指定的资源文件。
  • 只有一个属性resources,是个String数组。会从类加载器中去查询对应的资源文件是否存在;
@ConditionalOnResource(resources="mybatis.xml")
// 类加载路径中必须存在mybatis.xml文件
@ConditionalOnSingleCandidate OnBeanCondition Spring容器中是否存在且只存在一个对应的实例。
  • 只有3个属性“value”、“type”、“search”,跟ConditionalOnBean中的这3种属性值意义一样
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
// Spring当前或父容器中必须存在PlatformTransactionManager这个类型的实例,且只有一个实例
@ConditionalOnWebApplication OnWebApplicationCondition 应用程序是否是Web程序,没有提供属性,只是一个标识。
  • 会从判断Web程序特有的类是否存在,环境是否是Servlet环境,容器是否是Web容器等
@ConditionalOnWebApplication
// 必须在Web应用下才会生效

Maven下载源码

通过“dependency:sources”命令,可以下载该项目中所有的依赖的包的源码。