文章目录
3.1 Spring 注入组件的注解
3.1.1 @Component、@Controller、 @Service、@Repository
- 说明: 这些在 Spring 中的传统注解仍然有效,通过这些注解可以给容器注入组件
3.1.2 案例演示
- 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\A.java
package com.xjs.springboot.bean;
import org.springframework.stereotype.Repository;
/**
* @Author: 谢家升
* @Version: 1.0
*/
@Repository
public class A {
}
- 在 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java 获取,完成测试,其他几个注解就不测试了
package com.xjs.springboot;
import com.xjs.springboot.bean.A;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @Author: 谢家升
* @Version: 1.0
* @SpringBootApplication : 表示这是一个 springboot应用/项目
* @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组])
* 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"})
*/
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//如何查看容器中注入的组件
//String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
//for (String beanDefinitionName : beanDefinitionNames) {
// System.out.println("beanDefinitionName= " + beanDefinitionName);
//}
//演示Spring中传统的注解依然可以使用 @Controller @Service @Repository
A a = ioc.getBean(A.class);
System.out.println("a= " + a);
}
}
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.3)
a= com.xjs.springboot.bean.A@22101c80
3.2 @Configuration
3.2.1 应用实例
-
需求说明:
演示在 SpringBoot,如何通过@Configuration 创建配置类来注入组件
-
回顾传统方式如何通过配置文件注入组件
- 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\Monster.java
package com.xjs.springboot.bean;
/**
* @Author: 谢家升
* @Version: 1.0
*/
public class Monster {
private Integer id;
private String name;
private Integer age;
private String skill;
public Monster(Integer id, String name, Integer age, String skill) {
this.id = id;
this.name = name;
this.age = age;
this.skill = skill;
}
public Monster() {
}
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
@Override
public String toString() {
return "Monster{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", skill='" + skill + '\'' +
'}';
}
}
- 创建 D:\xjs_springboot\quickstart\src\main\resources\beans.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="monster01" class="com.xjs.springboot.bean.Monster">
<property name="name" value="牛魔王"></property>
<property name="age" value="666"></property>
<property name="skill" value="芭蕉扇"></property>
<property name="id" value="100"></property>
</bean>
</beans>
- 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java ,获取 Bean对象
package com.xjs.springboot;
import com.xjs.springboot.bean.A;
import com.xjs.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: 谢家升
* @Version: 1.0
* @SpringBootApplication : 表示这是一个 springboot应用/项目
* @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组])
* 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"})
*/
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//测试在springboot中依然可以使用spring的配置bean/注入bean/获取bean 的方式
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
Monster monster01 = ac.getBean("monster01", Monster.class);
System.out.println("monster01= " + monster01);
}
}
-----输出结果-----
monster01= Monster{id=100, name='牛魔王', age=666, skill='芭蕉扇'}
- 使用 SpringBoot 的@Configuration 添加/注入组件
- 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\config\BeanConfig.java
package com.xjs.springboot.config;
import com.xjs.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: 谢家升
* @Version: 1.0
* <p>
* 解读:
* 1. @Configuration 表示这是一个配置类,等价于配置文件[beans.xml]
* 2. 程序员可以通过 @Bean注解 注入bean对象到容器
* 3. 当一个类被 @Configuration 标识,该类对应的-Bean 也会注入到容器中
*/
@Configuration
public class BeanConfig {
/**
* 解读:
* 1. @Bean : 给容器添加组件,就是一个 Monster bean对象
* 2. monster02() : 默认 你的方法名 monster02 作为Bean的 id/名字
* 3. Monster : 注入类型,注入的bean的类型是 Monster
* 4. new Monster(200, "红孩儿", 300, "三味真火") : 注入到容器中具体的Bean信息
* 5. @Bean(name = "monster_hhe") : 在配置、注入Bean 指定名字/id 为 monster_hhe
* 6. 配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的
* 7. 如果想获取多例的,再加上 @Scope("prototype") 注解即可,每次获取的都是新的对象
* @return
*/
//@Bean(name = "monster_hhe")
@Bean
//@Scope("prototype")
public Monster monster02() {
return new Monster(200, "红孩儿", 300, "三味真火");
}
}
- 修改 MainApp.java , 从配置文件/容器获取 bean ,并完成测试
package com.xjs.springboot;
import com.xjs.springboot.bean.A;
import com.xjs.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: 谢家升
* @Version: 1.0
* @SpringBootApplication : 表示这是一个 springboot应用/项目
* @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组])
* 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"})
*/
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//测试在springboot中依然可以使用spring的配置bean/注入bean/获取bean 的方式
//=====传统方式开始=====
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
Monster monster01 = ac.getBean("monster01", Monster.class);
System.out.println("monster01= " + monster01);
//=====传统方式结束=====
//获取 BeanConfig 配置类的组件/bean 实例
Monster monster02 = ioc.getBean("monster02", Monster.class);
System.out.println("monster02= " + monster02);
//配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的
Monster monster03 = ioc.getBean("monster02", Monster.class);
System.out.println(monster02 == monster03);//true
}
}
- 也可以通过 Debug 来查看 ioc 容器是否存在 monster02 Bean 实例
- beanDefinitionMap,只是存放了 bean 定义信息
- 真正存放 Bean 实例的在singleonObjectis 的 Map 中
- 对于非单例,是每次动态反射生成的实例
3.2.2 @Configuration 注意事项和细节
- 配置类本身也是组件, 因此也可以获取,测试 修改 MainApp.java
package com.xjs.springboot;
import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
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: 谢家升
* @Version: 1.0
* @SpringBootApplication : 表示这是一个 springboot应用/项目
* @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组])
* 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"})
*/
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//=====演示 配置类-Bean 也会被注入到容器中 开始=====
BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
System.out.println("beanConfig= " + beanConfig);
//=====演示 配置类-Bean 也会被注入到容器中 结束=====
}
}
- SpringBoot2 新增特性: proxyBeanMethods 指定 Full 模式 和 Lite 模式
- 修改配置类 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\config\BeanConfig.java
package com.xjs.springboot.config;
import com.xjs.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* @Author: 谢家升
* @Version: 1.0
* <p>
* 解读:
* 1. @Configuration 表示这是一个配置类,等价于配置文件[beans.xml]
* 2. 程序员可以通过 @Bean注解 注入bean对象到容器
* 3. 当一个类被 @Configuration 标识,该类对应的-Bean 也会注入到容器中
*/
/**
* 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 {
/**
* 解读:
* 1. @Bean : 给容器添加组件,就是一个 Monster bean对象
* 2. monster02() : 默认 你的方法名 monster02 作为Bean的 id/名字
* 3. Monster : 注入类型,注入的bean的类型是 Monster
* 4. new Monster(200, "红孩儿", 300, "三味真火") : 注入到容器中具体的Bean信息
* 5. @Bean(name = "monster_hhe") : 在配置、注入Bean 指定名字/id 为 monster_hhe
* 6. 配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的
* 7. 如果想获取多例的,再加上 @Scope("prototype") 注解即可,每次获取的都是新的对象
* @return
*/
//@Bean(name = "monster_hhe")
@Bean
//@Scope("prototype")
public Monster monster02() {
return new Monster(200, "红孩儿", 300, "三味真火");
}
}
- 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java
package com.xjs.springboot;
import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
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: 谢家升
* @Version: 1.0
* @SpringBootApplication : 表示这是一个 springboot应用/项目
* @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组])
* 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"})
*/
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//=====演示 @Configuration(proxyBeanMethods = xxx) 开始=====
//1. 获取到 BeanConfig组件
BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
Monster monster_01 = beanConfig.monster02();
Monster monster_02 = beanConfig.monster02();
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("monster02", Monster.class);
Monster monster02 = ioc.getBean("monster02", Monster.class);
System.out.println("monster01= " + monster01 + " " + monster01.hashCode());
System.out.println("monster02= " + monster02 + " " + monster02.hashCode());
//=====演示 @Configuration(proxyBeanMethods = xxx) 结束=====
}
}
- 配置类可以有多个,就和 Spring 可以有多个 ioc 配置文件是一个道理
- 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\config\BeanConfig2.java
package com.xjs.springboot.config;
import com.xjs.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: 谢家升
* @Version: 1.0
*
* 第二个配置类
*/
@Configuration
public class BeanConfig2 {
@Bean
public Monster monster04() {
return new Monster(400, "狐狸精", 200, "美人计");
}
}
- 完成测试,修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java
package com.xjs.springboot;
import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
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: 谢家升
* @Version: 1.0
* @SpringBootApplication : 表示这是一个 springboot应用/项目
* @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组])
* 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"})
*/
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//=====演示 可以有多个配置类 开始=====
Monster monster04 = ioc.getBean("monster04", Monster.class);
Monster monster02 = ioc.getBean("monster02", Monster.class);
System.out.println("monster04= " + monster04);
System.out.println("monster02= " + monster02);
//=====演示 可以有多个配置类 结束=====
}
}
3.3 @Import
3.3.1 应用实例
- 说明:演示在 SpringBoot,如何通过 @Import 来注入组件
- 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\Dog.java
package com.xjs.springboot.bean;
/**
* @Author: 谢家升
* @Version: 1.0
*/
public class Dog {
}
- 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\Cat.java
package com.xjs.springboot.bean;
/**
* @Author: 谢家升
* @Version: 1.0
*/
public class Cat {
}
- 修改 BeanConfig.java 通过@Import 注入组件
package com.xjs.springboot.config;
import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope;
/**
* @Author: 谢家升
* @Version: 1.0
* <p>
* 解读:
* 1. @Configuration 表示这是一个配置类,等价于配置文件[beans.xml]
* 2. 程序员可以通过 @Bean注解 注入bean对象到容器
* 3. 当一个类被 @Configuration 标识,该类对应的-Bean 也会注入到容器中
*/
/**
* 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 模 也称为轻量级模式,因为不检测依赖关系,运行速度快
*/
/**
* 解读 :
* 1. @Import 注解 ,看源码可以知道,可以指定 class的数组,可以注入指定类型的Bean
* public @interface Import {
* Class<?>[] value();
* }
*
* 2. 通过 @Import 方式注入了组件,默认组件的 名字/id 就是对应类型的全类名
*/
@Import({Dog.class, Cat.class})
@Configuration
public class BeanConfig {
/**
* 解读:
* 1. @Bean : 给容器添加组件,就是一个 Monster bean对象
* 2. monster02() : 默认 你的方法名 monster02 作为Bean的 id/名字
* 3. Monster : 注入类型,注入的bean的类型是 Monster
* 4. new Monster(200, "红孩儿", 300, "三味真火") : 注入到容器中具体的Bean信息
* 5. @Bean(name = "monster_hhe") : 在配置、注入Bean 指定名字/id 为 monster_hhe
* 6. 配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的
* 7. 如果想获取多例的,再加上 @Scope("prototype") 注解即可,每次获取的都是新的对象
*
* @return
*/
//@Bean(name = "monster_hhe")
@Bean
//@Scope("prototype")
public Monster monster02() {
return new Monster(200, "红孩儿", 300, "三味真火");
}
}
- 修改 MainApp.java 完成测试
package com.xjs.springboot;
import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
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: 谢家升
* @Version: 1.0
* @SpringBootApplication : 表示这是一个 springboot应用/项目
* @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组])
* 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"})
*/
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//=====测试 @Import 使用 开始=====
Dog dog = ioc.getBean(Dog.class);
Cat cat = ioc.getBean(Cat.class);
System.out.println("dog= " + dog);
System.out.println("cat= " + cat);
//=====测试 @Import 使用 结束=====
}
}
3.4 @Conditional
3.4.1 @Conditional 介绍
- 条件装配:满足 Conditional 指定的条件,则进行组件注入
- @Conditional 是一个根注解,下面有很多扩展注解
@Conditional扩展注解 | 作用(判断是否满足当前指定条件) |
---|---|
@ConditionOnJava | 系统的Java版本是否符合要求 |
@ConditionOnBean | 容器中存在指定Bean |
@ConditionOnMissingBean | 容器中不存在指定Bean |
@ConditionOnExpression | 满足SpEL表达式指定 |
@ConditionOnClass | 系统中有指定的类 |
@ConditionOnMissingClass | 系统中没有指定的类 |
@ConditionOnSingleCandidate | 容器中只有一个指定的bean,或者这个bean是首选bean |
@ConditionOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是web环境 |
@ConditionalOnNoWebApplication | 当前不是web环境 |
@ConditionalOnJndi | JNDI存在指定项 |
3.4.2 应用实例
- 要求:演示在 SpringBoot,通过 @ConditionalOnBean 来注入组件
- 只有在容器中有 name = monster_nmw 组件时,才注入 dog01,代码如图
- 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\config\BeanConfig.java
package com.xjs.springboot.config;
import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope;
/**
* @Author: 谢家升
* @Version: 1.0
* <p>
* 解读:
* 1. @Configuration 表示这是一个配置类,等价于配置文件[beans.xml]
* 2. 程序员可以通过 @Bean注解 注入bean对象到容器
* 3. 当一个类被 @Configuration 标识,该类对应的-Bean 也会注入到容器中
* <p>
* 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 模式 也称为轻量级模式,因为不检测依赖关系,运行速度快
*/
/**
* 解读 :
* 1. @Import 注解 ,看源码可以知道,可以指定 class的数组,可以住人指定类型的Bean
* public @interface Import {
* Class<?>[] value();
* }
*
* 2. 通过 @Import 方式注入了组件,默认组件的 名字/id 就是对应类型的全类名
*/
@Import({Dog.class, Cat.class})
@Configuration
//@ConditionalOnBean(name = "monster_nmw")
public class BeanConfig {
/**
* 解读:
* 1. @Bean : 给容器添加组件,就是一个 Monster bean对象
* 2. monster02() : 默认 你的方法名 monster02 作为Bean的 id/名字
* 3. Monster : 注入类型,注入的bean的类型是 Monster
* 4. new Monster(200, "红孩儿", 300, "三味真火") : 注入到容器中具体的Bean信息
* 5. @Bean(name = "monster_hhe") : 在配置、注入Bean 指定名字/id 为 monster_hhe
* 6. 配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的
* 7. 如果想获取多例的,再加上 @Scope("prototype") 注解即可,每次获取的都是新的对象
*
* @return
*/
//@Bean(name = "monster_hhe")
@Bean
//@Scope("prototype")
public Monster monster02() {
return new Monster(200, "红孩儿", 300, "三味真火");
}
@Bean(name = "monster_nmw")
public Cat cat01() {
return new Cat();
}
/**
* 解读:
* 1. @ConditionalOnBean(name = "monster_nmw") 表示
* 2. 当容器中有一个Bean,它的名字是 monster_nmw (类型不做约束) 我们就注入 dog01 这个Dog Bean
* 3. 如果容器中中没有名字是 monster_nmw 的Bean,就不注入 dog01 这个Dog Bean
* 4. 还有很多其他的条件约束注解...
*
* 5. @ConditionalOnMissingBean(name = "monster_nmw") 表示
* 6. 在容器中没有 名字/id 为 monster_nmw 才注入dog01 这个Dog Bean
*
* 7. @ConditionalOnBean(name = "monster_nmw") 也可以标识配置类
* 表示对该配置类的所有要注入的组件,都进行条件约束
*
* @return
*/
@Bean
@ConditionalOnBean(name = "monster_nmw")
//@ConditionalOnMissingBean(name = "monster_nmw")
public Dog dog01() {
return new Dog();
}
}
- 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java ,完成测试
package com.xjs.springboot;
import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
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: 谢家升
* @Version: 1.0
* @SpringBootApplication : 表示这是一个 springboot应用/项目
* @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组])
* 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"})
*/
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//=====演示 @Conditional 的使用 开始=====
Dog dog01 = ioc.getBean("dog01", Dog.class);
System.out.println("dog01= " + dog01);
//=====演示 @Conditional 的使用 结束=====
}
}
3.5 @ImportResource
3.5.1 @ImportResource 介绍
- 作用:原生配置文件引入,也就是可以直接导入 Spring 传统的 beans.xml ,可以认为是 SpringBoot 对 Spring 容器文件的兼容
3.5.2 @ImportResource 应用实例
- 需求:将 beans.xml 导入到 BeanConfig.java 配置类, 并测试是否可以获得 beans.xml 注入/配置的组件
- 修改 BeanConfig.java / 或者创建新的 BeanConfig3.java(建议创建新的配置类) 来测试,使用@ImportResource 导入 beans.xml
package com.xjs.springboot.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
* @Author: 谢家升
* @Version: 1.0
*/
@Configuration
//导入beans.xml文件 -就可以获取到beans.xml文件中配置的bean
@ImportResource(locations = "classpath:beans.xml")
public class BeanConfig3 {
}
- 在 MainApp.java 测试
package com.xjs.springboot;
import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
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: 谢家升
* @Version: 1.0
* @SpringBootApplication : 表示这是一个 springboot应用/项目
* @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组])
* 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"})
*/
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
public static void main(String[] args) {
//启动springboot应用程序/项目
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//=====演示 @ImportResource 的使用 开始=====
Monster monster01 = ioc.getBean("monster01", Monster.class);
System.out.println("monster01= " + monster01);
System.out.println("monster01 bean 是否存在 => " + ioc.containsBean("monster01"));
//=====演示 @ImportResource 的使用 结束=====
}
}
3.6 配置绑定
3.6.1 基本介绍
- 使用 Java 读取到 SpringBoot 核心配置文件 application.properties 的内容
- 并且把它封装到 JavaBean 中
3.6.2 应用实例
- 需求:将 application.properties 指定的 k-v 和 JavaBean 绑定
#修改server的监听端口[默认是8080]
server.port=8888
#server.servlet.context-path=/abc
#修改文件上传的大小
#比如: 默认 spring.servlet.multipart.max-file-size=1MB
#解读:这个配置是在哪里读取的!
#该属性可以指定 springboot 上传文件大小的限制-体现约定优于配置
#默认配置最终都是映射到某个类上, 比如这里配置会 映射/关联 到 MultipartProperties[该类也会作为Bean注入到容器中]
#把光标放在该属性, ctrl+b 就可以定位该配置映射到的类(属性类)
spring.servlet.multipart.max-file-size=10MB
#自定义配置属性
my.website=https://www.baidu.com
#设置Furn的属性 k-v
#前面的 furn01 是用于指定/区分不同的绑定对象,这样可以在绑定Furn bean属性值时
#通过 furn01 前缀来进行区分
#furn01.id 中的id 就是 你要绑定的 Furn bean的属性名
furn01.id=100
furn01.name=TV
furn01.price=666.88
- 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\Furn.java
package com.xjs.springboot.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author: 谢家升
* @Version: 1.0
*/
/**
* 解读:
* 1. @Component 将 Furn 注册为一个组件
* 2. @ConfigurationProperties(prefix = "furn01") 指定在 application.properties 前缀
* 这样 Furn 组件就会属性文件中的 值绑定了
*/
@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;
}
@Override
public String toString() {
return "Furn{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
- 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\HiController.java
package com.xjs;
import com.xjs.springboot.bean.Furn;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
/**
* @Author: 谢家升
* @Version: 1.0
*/
@Controller
public class HiController {
//需求: website属性值 application.properties 的 k-v 来获取
@Value("${my.website}")
private String website;
//装配到 HiController
@Resource
private Furn furn;
@RequestMapping("/hi")
@ResponseBody
public String hi() {
System.out.println("website= " + website);
return "hi~, SpringBoot";
}
@RequestMapping("/furn")
@ResponseBody
public Furn furn() {
return furn;
}
}
- 启动 SpringBoot ,测试
- 配置绑定还有第 2 种方式,完成测试,效果一样
- 注意:如果注销 @Component ,需要在 BeanConfig.java (说明:也可以是其它配类) 配置
@EnableConfigurationProperties(Furn.class)
,否则会提示错误
//@EnableConfigurationProperties(Furn.class)解读
//1、开启 Furn 配置绑定功能
//2、把 Furn 组件自动注册到容器中
@EnableConfigurationProperties(Furn.class)
public class BeanConfig {
}
3.6.3 注意事项和细节
- 如果 application.properties 有中文,需要转成 unicode 编码写入,否则出现乱码
#设置Furn的属性 k-v
#前面的 furn01 是用于指定/区分不同的绑定对象,这样可以在绑定Furn bean属性值时
#通过 furn01 前缀来进行区分
#furn01.id 中的id 就是 你要绑定的 Furn bean的属性名
furn01.id=100
furn01.name=TV~~~\u7535\u89c6\u673a
furn01.price=666.88
- 使用
@ConfigurationProperties(prefix = "furn01")
会提示如下信息,但是不会影响使用
- 解决
@ConfigurationProperties(prefix = "furn01")
提示信息
- 在 pom.xml 增加依赖,即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>