一.获取bean对象
1.默认情况下,spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动的获取,这些bean,可以通过下面的方式
首先我们先注入一个IOC容器
@Autowired
private ApplicationContext applicationContext; //IOC容器对象
1.1根据name获取bean: Object getBean(String name)
//根据bean的名称获取
DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
//1.bean的名称没有设置,一般为首字母小写
//2.从IOC容器里用getBean()获得的bean对象一般为Object类,需要进行强转
System.out.println(bean1);
1.2根据类型获取bean:<T> T getBean(Class<T> requiredType)
//根据类型获取bean
DeptController bean2 = applicationContext.getBean(DeptController.class);
System.out.println(bean2);
1.3根据name获取bean(带类型转换):<T> T getBean(String name,Class<T> requireType)
//根据bean的名称 及 类型获取
DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
System.out.println(bean3);
运行: 从下面的输出中我们可以看出他们所调用的是同一个Bean对象(单例)
二.Bean的作用域
1.如何调用不同的Bean对象呢?
可以通过注解@Scope来设置作用域
1.默认情况调用的是单例
2.设置成非单例@Scope("prototype"),注意这里是在对应的Bean对象上面设置@Scope
像本例中就是在DeptController这个类上来设置注解@Scope
注意:
- 默认singleton的bean,在容器启动时,可以使用@lazy来延迟初始化(延迟到第一次使用时)
- prototype的bean,每一次使用该bean都会创建一个实例
- 实际开发中,绝大多数的bean是单例的,不需要配置@Scope
2.单例和多例
单例:只有一个共享实例的存在,所有对这个bean的请求都会返回这个唯一的实例,不管new多少次,即所有的请求都有一个对象来处理.
多例:对这个bean的每次请求都会创建一个新的bean实例,类似于new
2.1什么时候用单例?什么时候用多例?
答:当对象含有可改变状态时(在实际应用中该状态会改变),则多例,否则单例。例如dao和service层的数据一般不会有响应的属性改变,所以考虑单例,而Controller层会存储很多需要操作的vo类,此时这个对象的状态就会被改变,则需要使用多例
当对象含有可改变状态时(在实际应用中该状态会改变):简单理解下就是像手机,有各个品牌的手机,每个品牌手机中的硬件肯定是有差异的,每个品牌类型的手机对应的就是多例
2.2spring的bean为什么是单例的?
答:为了提高性能。
由于不会每次都新创建新对象,所以就减少了新生成实例的消耗。因为spring会通过反射或者cglib来生成bean实例这都是耗性能的操作,其次给对象分配内存也会涉及复杂算法。
减少JVM垃圾回收,由于不会给每个请求都新生成bean实例,所以自然回收的对象少了。
可以快速获取到bean,因为单例的获取bean操作除了第一次生成之外其余的都是从缓存里获取的所以很快。
三.第三方的Bean
1.本地的bean
都是通过@Component @Controller @Service @Repository注解声明bean对象后期要用的话通过@Autowired注入使用
2.第三方的bean
1.例子:
我们引入了Dom4j依赖,其中包含SAXReader()这个类我么可以new这个类来解析xml文件
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
//第三方bean的管理
@Test
public void testThirdBean() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(this.getClass().getClassLoader().getResource("1.xml"));
Element rootElement = document.getRootElement();
String name = rootElement.element("name").getText();
String age = rootElement.element("age").getText();
System.out.println(name + " : " + age);
}
问题:如果我们每次都 new SAXReader()实例的话耗费资源,如何声明SAXReader呢?
1.我们可以不可以通过在其类中写入@component注解将该类放入IOC容器中
不可以,通过依赖引入的文件是只读的不允许修改(File is read-only)
2.那我们该如何声明呢?
通过@bean注解:在springboot启动类中定义这样一个方法
@Bean
public SAXReader saxReader(){
return new SAXReader();
}
在该方法上加了一个@bean,那么在程序在启动类执行的时候,他就会自动创建这个方法,并将其方法的返回值交给IOC容器,成为IOC容器中的Bean对象,如果你在后面想要使用直接注入就好了(后面我们会使用@Configuration定义配置类,将我们所需的都放在配置类中,保证启动类只进行启动
3.声明后第三方bean对象叫什么名字呢?
通过name或者value来指定名称 例: @Bean(name="hello")
如果没有指定,则默认为方法名,即:上述SAXReader的名字为saxer
4.如果我们在声明第三方bean的时候要进行依赖注入怎么办?
直接在其对应的方法形参上写.例如:现在想注入DeptSevice这个类型
@Bean(name="hello")
public SAXReader saxReader(DeptService deptService){
//在这里使用@Autowired注入DeptService是错误的
return new SAXReader();
}