SpringBoot-容器功能
1.Spring 注入组件的注解
1.@Component、@Controller、 @Service、@Repository
说明: 这些在 Spring 中的传统注解仍然有效,通过这些注解可以给容器注入组件
2.案例演示
1.创建src\main\java\com\llp\bean\A.java
@Repository
public class A {
}
2.修改MainApp.java主启动类
@SpringBootApplication(scanBasePackages = {"com"})
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
//演示spring中传统的注解依然可以使用@Controller @Service @Repository
A bean = ioc.getBean(A.class);
//com.llp.bean.A@6c17c0f8
System.out.println(bean);
}
}
A类被@Repository修饰,可以看到A被注入到了Spring的ioc容器中,而默认的以类名首字母小写的方式作为bean的id
2.@Configuration
1.应用实例
● @Configuration 应用实例需求
演示在 SpringBoot, 如何通过@Configuration 创建配置类来注入组件
● 回顾传统方式如何通过配置文件注入组件
1.创建src\main\java\com\llp\bean\Monster.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Monster {
private Integer id;
private String name;
private Integer age;
private String skill;
}
2.创建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">
<bean id="monster03" class="com.llp.bean.Monster">
<property name="id" value="100"/>
<property name="name" value="孙悟空"/>
<property name="age" value="1000"/>
<property name="skill" value="刷光棍"/>
</bean>
</beans>
3.修改主启动类
@SpringBootApplication(scanBasePackages = {"com"})
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
Monster monster03 = ac.getBean("monster03", Monster.class);
//Monster(id=100, name=孙悟空, age=1000, skill=刷光棍)
System.out.println(monster03);
}
}
SpringBoot是支持传统的方式去获取bean对象的
● 使用 SpringBoot 的@Configuration 添加/注入组件
1.创建src\main\java\com\llp\config\BeanConfig.java
@Configuration
public class BeanConfig {
/**
* 1. @Bean : 给容器添加组件, 就是Monster bean
* 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
* 3. Monster : 注入类型, 注入bean的类型是Monster
* 4. new Monster(200,"库里林",200,"铁头功") 注入到容器中具体的Bean
* 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字
* 6. 默认是单例注入
* 7. 通过 @Scope("prototype") 可以每次返回新的对象,就多例.
*/
//@Bean(name = "monster_nmw")
@Bean
//@Scope("prototype")
public Monster monster01(){
return new Monster(200,"库里林",200,"铁头功");
}
}
2.修改主启动类,进行测试
@SpringBootApplication(scanBasePackages = {"com"})
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
Monster monster01 = ioc.getBean("monster01", Monster.class);
//Monster(id=200, name=库里林, age=200, skill=铁头功)
System.out.println(monster01);
}
}
debug查看ioc容器
beanDefinitionMap, 只是存放了 bean 定义信息, 真正存放 Bean 实例的在 singleonObjectis 的 Map 中, 对于非单例,是每次动态反射生成的实例
2.@Configuration注意事项和细节
- 配置类本身也是组件, 因此也可以获取, 测试 修改 MainApp.java
- SpringBoot2 新增特性: proxyBeanMethods 指定 Full 模式 和 Lite 模式
(1)修改src\main\java\com\llp\config\BeanConfig.java 设置proxyBeanMethods = true(默认为true)
/**
* 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 = true)
public class BeanConfig {
/**
* 1. @Bean : 给容器添加组件, 就是Monster bean
* 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
* 3. Monster : 注入类型, 注入bean的类型是Monster
* 4. new Monster(200,"库里林",200,"铁头功") 注入到容器中具体的Be
* 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字
* 6. 默认是单例注入
* 7. 通过 @Scope("prototype") 可以每次返回新的对象,就多例.
*/
//@Bean(name = "monster_nmw")
@Bean
//@Scope("prototype")
public Monster monster01(){
return new Monster(200,"库里林",200,"铁头功");
}
}
修改主程序进行测试
@SpringBootApplication(scanBasePackages = {"com"})
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
BeanConfig bean = ioc.getBean(BeanConfig.class);
Monster monster01 = bean.monster01();
Monster monster02 = bean.monster01();
//monster01 --- 1533783975
System.out.println("monster01 --- " + monster01.hashCode());
//monster02 --- 1533783975
System.out.println("monster02 --- " + monster02.hashCode());
}
}
Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式】
(2)修改src\main\java\com\llp\config\BeanConfig.java 设置proxyBeanMethods = fasle
/**
* 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. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
* 3. Monster : 注入类型, 注入bean的类型是Monster
* 4. new Monster(200,"库里林",200,"铁头功") 注入到容器中具体的Be
* 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字
* 6. 默认是单例注入
* 7. 通过 @Scope("prototype") 可以每次返回新的对象,就多例.
*/
//@Bean(name = "monster_nmw")
@Bean
//@Scope("prototype")
public Monster monster01(){
return new Monster(300,"库里林",200,"铁头功");
}
}
这里要注意一个坑,在前面我们使用lombok的@Data注解会重新hashCode方法如下图,这样会导致一个问题,只要我们对象属性的值一样那么计算出来的hashCode值就是一样的,因此要验证(lite模式)轻量级模式就需要去修改Monster.java不要使用lombok @Data注解的方式
- 配置类可以有多个, 就和 Spring 可以有多个 ioc 配置文件是一个道理.
(1)创建src\main\java\com\llp\config\BeanConfig2.java
@Configuration
public class BeanConfig2 {
@Bean
public Monster monster02() {
return new Monster(800,"蚂蚁精",80,"吃小昆虫");
}
}
(2)修改主启动类测试
@SpringBootApplication(scanBasePackages = {"com"})
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
Monster monster02 = ioc.getBean("monster02", Monster.class);
//Monster(id=800, name=蚂蚁精, age=80, skill=吃小昆虫)
System.out.println(monster02);
}
}
3.@Import
1.应用实例
演示在 SpringBoot, 如何通过 @Import 来注入组件
1.创建src\main\java\com\llp\bean\Cat.java和src\main\java\com\llp\bean\Dog.java
public class Cat {
}
public class Dog {
}
2.创建src\main\java\com\llp\config\BeanConfig3.java,采用@Import({Dog.class, Cat.class})的方式注入bean到ioc容器中
/**
* 1. @Import 代码 可以看到,可以指定 class的数组, 可以注入指定类型的Bean
* public @interface Import {
*
* Class<?>[] value()}
*
* 2. 通过@Import 方式注入了组件, 默认组件名字/id就是对应类型的全类名
*/
@Import({Dog.class, Cat.class})
@Configuration
public class BeanConfig3 {
}
3.运行主程序,查看ioc容器单例池
4.@Conditional
1.@Conditional 介绍
- 条件装配:满足 Conditional 指定的条件,则进行组件注入
- @Conditional 是一个根注解,下面有很多扩展注解
3.@Conditional扩展注解应用场景
2.应用实例
- 要求: 演示在 SpringBoot, 如何通过 @ConditionalOnBean 来注入组件
- 只有在容器中有 name = cat007组件时,才注入 dog01, 代码如下
@Bean(name = "cat007")
public Cat cat01(){
return new Cat();
}
/**
* 1. @ConditionalOnBean(name = "cat007") 表示
* 2. 当容器中有一个Bean , 名字是cat007 (类型不做约束), 就注入dog01这个Dog bean
* 3. 如果没有 名字是cat007 的Bean 就不注入dog01这个Dog bean
* 4. @ConditionalOnMissingBean(name = "cat007") 表示在容器中,
* 没有 名字/id 为 cat007 才注入dog01这个Bean
* 5. @ConditionalOnBean(name = "cat007") 也可以放在配置类
* 表示对该配置类的所有要注入的组件,都进行条件约束.
*/
@Bean
@ConditionalOnBean(name = "cat007")
public Dog dog01(){
return new Dog();
}
5.@ImportResource
1.作用
原生配置文件引入, 也就是可以直接导入 Spring 传统的 beans.xml ,可以认为是 SpringBoot 对 Spring 容器文件的兼容.
不使用@ImportResource引入,从ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
ioc中是获取不到bean的
2.@ImportResource 应用实例
- 需求: 将 beans.xml 导入到 BeanConfig.java 配置类, 并测试是否可以获得 beans.xml 注入/配置的组件
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">
<bean id="monster03" class="com.llp.bean.Monster">
<property name="id" value="100"/>
<property name="name" value="孙悟空"/>
<property name="age" value="1000"/>
<property name="skill" value="刷光棍"/>
</bean>
</beans>
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.llp.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>
- 创建新的 BeanConfig4.java来测试, 使用@ImportResource 导入 beans.xml、beans02.xml
/**
* @Retention(RetentionPolicy.RUNTIME)
* @Target({ElementType.TYPE})
* @Documented
* public @interface ImportResource {
* @AliasFor("locations")
* String[] value() default {};
*
* @AliasFor("value")
* String[] locations() default {};
*
* Class<? extends BeanDefinitionReader> reader() default BeanDefinitionReader.class;
* }
*/
@Configuration
@ImportResource(locations = {"classpath:beans.xml","classpath:beans02.xml"})
public class BeanConfig4 {
}
3.运行主启动类,进行测试
6.配置绑定
1.作用
一句话:使用 Java 读取到 SpringBoot 核心配置文件 application.properties 的内容, 并且把它封装到 JavaBean 中
2.应用实例
- 需求: 将 application.properties 指定的 k-v 和 JavaBean 绑定
在application.properties文件中加入
furn01.id=100
furn01.name=悟空
furn01.price=0.02
创建src\main\java\com\llp\bean\Furn.java
这里javaBean需要提供get和set方法,在容器启动时会利用反射调用set方法进行赋值,在获取bean进行序列化时会调用get方法
@Data
@Component
@ConfigurationProperties(prefix = "furn01")
public class Furn {
private Integer id;
private String name;
private Double price;
}
修改HelloController.java
@RestController
public class HelloController {
@Autowired
private Furn furn;
@RequestMapping("/hello")
public String hello(){
return "hello SpringBoot";
}
@RequestMapping("/furn")
public Furn furn(){
System.out.println(furn);
return furn;
}
}
启动容器访问测试
3.注意事项和细节
- 如果 application.properties 有中文, 需要转成 unicode 编码写入, 否则出现乱码;也可以设置idea工具的编码格式
- 使用 @ConfigurationProperties(prefix = “furn01”) 会提示如下信息, 但是不会影响使用
- 解决 @ConfigurationProperties(prefix = “furn01”) 提示信息, 在 pom.xml 增加依赖, 即可
4.配置绑定还可以在配置类中添加 @EnableConfigurationProperties({Furn.class})
配置如下:
@Data
//@Component
@ConfigurationProperties(prefix = "furn01")
public class Furn {
private Integer id;
private String name;
private Double price;
}
@Configuration
@EnableConfigurationProperties({Furn.class})
public class BeanConfig5 {
}
重启测试,发现也是可以的
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/81267.html