容器功能
Spring 注入组件的注解
@Component、@Controller、 @Service、@Repository
这些在 Spring 中的传统注解仍然有效,通过这些注解可以给容器注入组件。
@Configuration
应用实例
通过 @Configuration 创建配置类来注入组件。
创建 src/main/java/com/lzw/springboot/config/BeanConfig.java
package com.lzw.springboot.config;
import com.lzw.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author LiAng
* 1. @Configuration 标识这是一个配置类, 等价于配置文件
* 2. 程序员可以通过@Bean 注解注入bean对象到容器
* 3. 当一个类被 @Configuration 标识,该类-Bean 也会注入容器
*/
@Configuration
public class BeanConfig {
/**
* 1. @Bean : 给容器添加组件, 就是Monster bean
* 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
* 3. Monster : 注入类型, 注入bean的类型是Monster
* 4. new Monster(200,"牛魔王",500,"疯魔拳") 注入到容器中具体的Bean信息
* 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字/id monster_nmw
* 6. 默认是单例注入
* 7. 通过 @Scope("prototype") 可以每次返回新的对象,就多例.
* @return
*/
//@Bean(name = "monster_nmw")
@Bean
//@Scope("prototype")
public Monster monster01(){
return new Monster(200, "牛魔王", 500, "疯魔拳");
}
}
修改 MainApp.java
package com.lzw.springboot;
import com.lzw.springboot.bean.A;
import com.lzw.springboot.bean.Monster;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author LiAng
*/
@SpringBootApplication(scanBasePackages = "com.lzw")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
Monster monster01 = ioc.getBean("monster01", Monster.class);
Monster monster02 = ioc.getBean("monster01", Monster.class);
System.out.println("monster01: "+monster01+" " + monster01.hashCode());
System.out.println("monster02: "+monster02+" " + monster02.hashCode());
}
}
注意事项和细节
- 配置类本身也是组件, 因此也可以获取。
@SpringBootApplication(scanBasePackages = "com.lzw")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
BeanConfig bean = ioc.getBean(BeanConfig.class);
System.out.println("bean--" + bean);
}
}
- SpringBoot2 新增特性: proxyBeanMethods 指定 Full 模式 和 Lite 模式。
修改 BeanConfig.java
package com.lzw.springboot.config;
import com.lzw.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* @author LiAng
*/
/**
* 1. proxyBeanMethods:代理bean的方法
* (1) Full(proxyBeanMethods = true)【保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式,默认】
* (2) Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的, 是非代理方式】
* (3) 特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法
* 而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效
* (4) 如何选择: 组件依赖必须使用Full模式默认。如果不需要组件依赖使用 Lite模
* (5) Lite模 也称为轻量级模式,因为不检测依赖关系,运行速度快
*/
@Configuration(proxyBeanMethods = false)
public class BeanConfig {
@Bean
public Monster monster01(){
return new Monster(200, "牛魔王", 500, "疯魔拳");
}
}
修改 MainApp.java
@SpringBootApplication(scanBasePackages = "com.lzw")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//先得到BeanConfig组件
BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
Monster monster_01 = beanConfig.monster01();
Monster monster_02 = beanConfig.monster01();
System.out.println("monster_01-" + monster_01 + " " + monster_01.hashCode());
System.out.println("monster_02-" + monster_02 + " " + monster_02.hashCode());
//特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法
//而不是直接通过 SpringBoot 主程序得到的容器来获取bean,
// 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效
Monster monster01 = ioc.getBean("monster01", Monster.class);
Monster monster02 = ioc.getBean("monster01", Monster.class);
System.out.println("monster01-" + monster01 + " " + monster01.hashCode());
System.out.println("monster02-" + monster02 + " " + monster02.hashCode());
}
}

- 配置类可以有多个,就和 Spring 可以有多个 ioc 配置文件是一个道理。
创建 src/main/java/com/lzw/springboot/config/BeanConfig2.java
package com.lzw.springboot.config;
import com.lzw.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author LiAng
* 这是第二个配置类
*/
@Configuration
public class BeanConfig2 {
@Bean
public Monster monster02(){
return new Monster(800, "蚂蚁精", 80, "吃小昆虫");
}
}
修改 MainApp.java
@SpringBootApplication(scanBasePackages = "com.lzw")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
Monster monster02 = ioc.getBean("monster02", Monster.class);
Monster monster01 = ioc.getBean("monster01", Monster.class);
System.out.println("monster02--" + monster02);
System.out.println("monster01--" + monster01);
}
}

@Import
应用实例
通过 @Import 来注入组件。
创建 src/main/java/com/lzw/springboot/bean/Dog.java
创建 src/main/java/com/lzw/springboot/bean/Cat.java
修改 BeanConfig.java
/**
* 1. @Import 代码 可以看到,可以指定 class的数组, 可以注入指定类型的Bean
* public @interface Import {
*
* Class<?>[] value()
* }
*
* 2. 通过@Import 方式注入了组件, 默认组件名字/id就是对应类型的全类名
*/
@Import({Dog.class, Cat.class})
@Configuration
public class BeanConfig {
}
修改 MainApp.java
@SpringBootApplication(scanBasePackages = "com.lzw")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
Monster monster02 = ioc.getBean("monster02", Monster.class);
Monster monster01 = ioc.getBean("monster01", Monster.class);
System.out.println("monster02--" + monster02);
System.out.println("monster01--" + monster01);
}
}

@Conditional
介绍
条件装配:满足 Conditional 指定的条件,则进行组件注入。
@Conditional 是一个根注解,下面有很多扩展注解。
@Conditional扩展注解 | 作用(判断是否满足当前指定条件) |
---|---|
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定Bean |
@ConditionalOnMissingBean | 容器中不存在指定Bean |
@ConditionalOnExpression | 满足SpEL表达式 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是web环境 |
@ConditionalOnNotWebApplication | 当前不是web环境 |
@ConditionalOnJndi | JNDI存在指定项 |
应用实例
要求:通过 @ConditionalOnBean 来注入组件,只有在容器中有 name = monster_nmw 组件时,才注入 dog01。
修改 BeanConfig.java
public class BeanConfig {
@Bean(name = "monster_nmw")
public Monster monster01(){
return new Monster(200, "牛魔王", 500, "疯魔拳");
}
@Bean
/**
* 1. @ConditionalOnBean(name = "monster_nmw") 表示
* 2. 当容器中有一个Bean , 名字是monster_nmw (类型不做约束), 就注入dog01这个Dog bean
* 3. 如果没有 名字是monster_nmw Bean 就不注入dog01这个Dog bean
* 4. @ConditionalOnMissingBean(name = "monster_nmw") 表示在容器中,
* 没有 名字/id 为 monster_nmw 才注入dog01这个Bean
* 5. @ConditionalOnBean(name = "monster_nmw") 也可以放在配置类
* 表示对该配置类的所有要注入的组件,都进行条件约束.
*/
@ConditionalOnBean(name = "monster_nmw")
public Dog dog01(){
return new Dog();
}
}
修改 MainApp.java
@SpringBootApplication(scanBasePackages = "com.lzw")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
System.out.println("容器是否注入了 dog01= " + ioc.containsBean("dog01"));
}
}

@ImportResource
作用
原生配置文件引入,也就是可以直接导入 Spring 传统的 beans.xml ,可以认为是 SpringBoot 对 Spring 容器文件的兼容。
应用实例
需求:将 beans.xml,beans02.xml 导入到 BeanConfig3.java 配置类,并测试是否可以获得 beans.xml 注入/配置的组件。
创建 resources/beans02.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置了Monster bean-->
<bean id="monster04" class="com.lzw.springboot.bean.Monster">
<property name="name" value="狐狸精"></property>
<property name="age" value="9000"></property>
<property name="skill" value="美人计"></property>
<property name="id" value="2000"></property>
</bean>
</beans>
创建 src/main/java/com/lzw/springboot/config/BeanConfig3.java
package com.lzw.springboot.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
* @author LiAng
*/
@Configuration
//导入beans.xml - 就可以获取到beans.xml 中配置bean
@ImportResource(locations = {"classpath:beans.xml","classpath:beans02.xml"})
public class BeanConfig3 {
}
修改 MainApp.java
@SpringBootApplication(scanBasePackages = "com.lzw")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
Monster monster03 = ioc.getBean("monster03", Monster.class);
System.out.println("monster03-" + monster03);
System.out.println("monster04 bean 是否存在-" + ioc.containsBean("monster04"));
}
}
配置绑定
使用 Java 读取到 SpringBoot 核心配置文件 application.properties 的内容, 并且把它封装到 JavaBean 中。
应用实例
需求:将 application.properties 指定的 k-v 和 JavaBean 绑定
创建 src/main/java/com/lzw/springboot/bean/Furn.java
package com.lzw.springboot.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author LiAng
*/
@Component
@ConfigurationProperties(prefix = "furn01")
public class Furn {
private Integer id;
private String name;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
修改 application.properties
#设置Furn的属性k-v
#前面的 furn01 是用于指定/区别不同的绑定对象, 这样可以再绑定Furn bean属性值时
#通过furn01 前缀进行区分
#furn01.id 中的id 就是你要绑定的 Furn bean的属性名
furn01.id=100
furn01.name=TV~~\u7535\u89c6\u673a
furn01.price=1999.99
修改 HiController
@Controller
public class HiController {
//装配到 HiController
@Resource
private Furn furn;
@RequestMapping("/furn")
@ResponseBody
public Furn furn(){
return furn;
}
}
配置绑定还有第 2 种方式,效果一样


注意事项和细节
- 如果 application.properties 有中文,需要转成 unicode 编码写入,否则出现乱码。
- 使用
@ConfigurationProperties(prefix = "furn01")
会提示如下信息,但是不会影响使用

导入依赖即可解决
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>