SpringBoot 如何从容器中获取对象
目录
- 如何从容器中获取对象
- SpringBoot中的容器
- 容器功能
- 1、组件添加
- 2、原生配置文件引入(xml文件引入)
- 3、配置绑定
如何从容器中获取对象
有时候在项目中,我们会自己创建一些类,类中需要使用到容器中的一些类。方法是新建类并实现ApplicationContextAware 接口,在类中建立静态对象 ApplicationContext 对象,这个对象就如同xml配置中的 applicationContext.xml,容器中类都可以获取到。
例如@Service、 @Component、@Repository、@Controller 、@Bean 标注的类都能获取到。
/** * 功能描述:Spring Bean 管理类 * */ @Component public class SpringContextUtils implements ApplicationContextAware { /** * 上下文对象实例 */ private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /** * 获取applicationContext * * @return */ public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 通过name获取 Bean. * * @param name * @return */ public static Object getBean(String name) { return getApplicationContext().getBean(name); } /** * 通过class获取Bean. * * @param clazz * @param <T> * @return */ public static <T> T getBean(Class<T> clazz) { try{ return getApplicationContext().getBean(clazz); }catch (Exception e){ return null; } } /** * 通过name,以及Clazz返回指定的Bean * * @param name * @param clazz * @param <T> * @return */ public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
SpringBoot中的容器
容器功能
1、组件添加
(1)主要注解
@Configuration
告诉SpringBoot这是一个配置类 == 配置文件
注意:spring5.2以后@Configuration多了一个属性proxyBeanMethods,默认为true
@Configuration(proxyBeanMethods = true)
proxyBeanMethods
:代理bean的方法Full(proxyBeanMethods = true)
、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】 外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象Lite(proxyBeanMethods = false)
【每个@Bean方法被调用多少次返回的组件都是新创建的】- 组件依赖必须使用Full模式默认。其他默认是否Lite模式
● Full模式与Lite模式
○ 最佳实战
■ 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
■ 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
@Bean
- 给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
- 配置类里面使用@Bean标注在方法上给容器注册组件,默认是单实例的
- 配置类本身也是组件
(2) 基本使用
bean包:
Pet类:
/** * 宠物 */ public class Pet { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Pet(String name) { this.name = name; } public Pet() { } @Override public String toString() { return "Pet{" + "name='" + name + '\'' + '}'; } }
User类:
/* 用户 */ public class User { private String name; private Integer age; public User() { } public User(String name, Integer age) { this.name = name; this.age = age; } 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; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
config包:
MyConfig类
@Configuration(proxyBeanMethods = false)//告诉Spring这是一个配置类 public class MyConfig { @Bean//给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例 public User user01(){ return new User("zhangsan",18); } @Bean("tom") public Pet tomcatPet(){ return new Pet("tomcat"); } }
controller包:
MainApplication类
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com") public class MainApplication { public static void main(String[] args) { //1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //2、查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } //3、从容器中获取组件 MyConfig bean = run.getBean(MyConfig.class); System.out.println(bean); //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。 //保持组件单实例 User user = bean.user01(); User user1 = bean.user01(); System.out.println("组件为:"+(user == user1)); } }
结果
(3)补充 @Import
给容器导入一个组件
必须写在容器中的组件上
* @Import({User.class, DBHelper.class}) * 给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名 * * * */ @Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 public class MyConfig { }
@Configuration测试代码如下
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com") public class MainApplication { public static void main(String[] args) { //1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //2、查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } //3、从容器中获取组件 MyConfig bean = run.getBean(MyConfig.class); System.out.println(bean); //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。 //保持组件单实例 User user = bean.user01(); User user1 = bean.user01(); System.out.println("组件为:"+(user == user1)); //5、获取组件 String[] beanNamesForType = run.getBeanNamesForType(User.class); System.out.println("======"); for (String s : beanNamesForType) { System.out.println(s); } DBHelper bean1 = run.getBean(DBHelper.class); System.out.println(bean1); } }
@Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
ConditionalOnBean
:当容器中存在指定的bean组件时才干某些事情ConditionalOnMissingBean
:当容器中不存在指定的bean组件时才干某些事情ConditionalOnClass
:当容器中有某个类时才干某些事情ConditionalOnResource
:当项目的类路径存在某个资源时,才干什么事
=====================测试条件装配========================== @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 //@ConditionalOnBean(name = "tom") @ConditionalOnMissingBean(name = "tom") public class MyConfig { @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例 public User user01(){ User zhangsan = new User("zhangsan", 18); //user组件依赖了Pet组件 zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean("tom22") public Pet tomcatPet(){ return new Pet("tomcat"); } }
测试:
public static void main(String[] args) { //1、返回我们IOC容器 ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); //2、查看容器里面的组件 String[] names = run.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } boolean tom = run.containsBean("tom"); System.out.println("容器中Tom组件:"+tom); boolean user01 = run.containsBean("user01"); System.out.println("容器中user01组件:"+user01); boolean tom22 = run.containsBean("tom22"); System.out.println("容器中tom22组件:"+tom22); }
2、原生配置文件引入(xml文件引入)
@ImportResource
导入资源
@ImportResource("classpath:beans.xml")//导入spring的配置文件 @Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false)//告诉Spring这是一个配置类 @ConditionalOnMissingBean(name = "tom") public class MyConfig {
======================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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <bean id="haha" class="com.atguigu.boot.bean.User"> <property name="name" value="zhangsan"></property> <property name="age" value="18"></property> </bean> <bean id="hehe" class="com.atguigu.boot.bean.Pet"> <property name="name" value="tomcat"></property> </bean> </beans>
测试
======================测试================= boolean haha = run.containsBean("haha"); boolean hehe = run.containsBean("hehe"); System.out.println("haha:"+haha);//true System.out.println("hehe:"+hehe);//true
3、配置绑定
如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用;
(1) @Component + @ConfigurationProperties
properties文件
/** * 只有在容器中的组件,才会拥有SpringBoot提供的强大功能 */ @Component @ConfigurationProperties(prefix = "mycar") public class Car { private String brand; private Integer price; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } @Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; } }
(2) @EnableConfigurationProperties + @ConfigurationProperties
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 @ConditionalOnMissingBean(name = "tom") @ImportResource("classpath:beans.xml") //@EnableConfigurationProperties(Car.class) //1、开启Car配置绑定功能 //2、把这个Car这个组件自动注册到容器中 public class MyConfig {
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。