Spring IoC基础
BeanFactory与ApplicationContext区别
Java环境下启动IoC容器
- ClassPathXmlApplicationContext:从类的根路径下加载配置文件(推荐使用)
- FileSystemXmlApplicationContext:从磁盘路径上加载配置文件
- AnnotationConigApplicationContext:纯注解模式下启动Spring容器
@org.junit.Test
public void testIoc(){
// 通过读取classpath下的xml文件来启动容器(xml模式SE应用下推荐)
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 不推荐使用
//ApplicationContext applicationContext1 = new FileSystemXmlApplicationContext("文件系统的绝对路径");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
}
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置Spring ioc容器的配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--使用监听器启动Spring的IOC容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
完全使用注解,从配置类启动容器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--告诉ContextloaderListener知道我们使用注解的方式启动ioc容器-->
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<!--配置启动类的全限定类名-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.bigdata.edu.SpringConfig</param-value>
</context-param>
<!--使用监听器启动Spring的IOC容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Spring IOC实例化bean的三种方式:
<!--配置service对象-->
<beanid="userService"class="com.bigdata.service.impl.TransferServiceImpl"></bean>
方式二和方式三是为了我们自己new的对象加入到SpringIOC容器管理中
<bean id="connectionUtils" class="com.bigdata.edu.factory.CreateBeanFactory" factory-method="getInstanceStatic"/>
<bean id="createBeanFactory" class="com.bigdata.edu.factory.CreateBeanFactory"></bean>
<bean id="connectionUtils" factory-bean="createBeanFactory" factory-method="getInstance"/>
public class CreateBeanFactory {
public static ConnectionUtils getInstanceStatic() {
return new ConnectionUtils();
}
public ConnectionUtils getInstance() {
return new ConnectionUtils();
}
}
Bean的作用范围及生命周期
singleton:单例,IOC容器中只有一个该类对象,默认为singleton
prototype:原型(多例),每次使用该类的对象(getBean),都返回给你一个新的对象,Spring只创建对象,不管理对象
单例模式:singleton
对象出生:当创建容器时,对象就被创建了。
对象活着:只要容器在,对象一直活着。
对象死亡:当销毁容器时,对象就被销毁了。
一句话总结:单例模式的bean对象生命周期与容器相同。
多例模式:prototype
对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被java的垃圾回收器回收了。
一句话总结:多例模式的bean对象,spring框架只负责创建,不负责销毁。
Spring IOC高级特性
1、lazy-Init 延迟加载
<beanid="testBean"class="cn.lagou.LazyBean"/>
//该bean默认的设置为:
<beanid="testBean"calss="cn.lagou.LazyBean"lazy-init="false"/>
2、FactoryBean 和 BeanFactory
BeanFactory接口是容器的顶级接口,定义了容器的一些基础行为,负责生产和管理Bean的一个工厂,具体使用它下面的子接口类型,比如ApplicationContext;此处我们重点分析FactoryBean
Spring中Bean有两种,一种是普通Bean,一种是工厂Bean(FactoryBean),FactoryBean可以生成某一个类型的Bean实例(返回给我们),也就是说我们可以借助于它自定义Bean的创建过程。Bean创建的三种方式中的静态方法和实例化方法和FactoryBean作用类似,FactoryBean使用较多,尤其在Spring框架一些组件中会使用,还有其他框架和Spring框架整合时使用。
3 、后置处理器
Spring提供了两种后处理bean的扩展接口,分别为 BeanFactoryPostProcessor和BeanPostProcessor ,两者在使用上是有所区别的。
工厂初始化(BeanFactory)—> Bean对象
在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置处理做一些事情
在Bean对象实例化(并不是Bean的整个生命周期完成)之后可以使用BeanPostProcessor进行后置处理做一些事情
BeanDefinition对象:
BeanFactoryPostProcessor
是BeanFactory级别的处理,是针对整个Bean的工厂进行处理,典型应用:PropertyPlaceholderConigurer
此接口只提供了一个方法,方法参数为ConigurableListableBeanFactory,该参数类型定义了一些方法
SpringBean的生命周期:
* spring启动时,spring读取加载xml配置文件中bean的信息,解析成一个一个BeanDefinition对象
* springBean 的生命周期
* 1.通过new或反射方式实例化bean
* 2.依赖依赖注入返程所有属性的赋值
* 3.如果bean实现了BeanNameAware接口,则bean调用setBeanName方法,则可以拿到注册我成为bean时定义的id
* 4.如果bean实现了BeanFactoryAware接口,则bean调用setBeanFactory方法,可以拿到bean的外部环境工厂实例对象
* 5.实现ApplicationContextAware接口,bean调用setApplicationContext,可以拿到高级容器接口
* 6.BeanPostProcessor是bean级别的处理,可以拦截到所有bean,调用预处理化postProcessBeforeInitialization方法可以,可以对bean进行预加工
* before方法在自定义iniMethod之前
* 7.
package com.bigdata.edu.pojo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* spring启动时,spring读取加载xml配置文件中bean的信息,解析成一个一个BeanDefinition对象
* springBean 的生命周期
* 1.通过new或反射方式实例化bean,读取配置文件时已经把<bean>解析成一个一个BeanDefinition对象了
* 2.依赖依赖注入返程所有属性的赋值
* 3.如果bean实现了BeanNameAware接口,则bean调用setBeanName方法,则可以拿到注册我成为bean时定义的id
* 4.如果bean实现了BeanFactoryAware接口,则bean调用setBeanFactory方法,可以拿到bean的外部环境工厂实例对象
* 5.实现ApplicationContextAware接口,bean调用setApplicationContext,可以拿到高级容器接口
* 6.BeanPostProcessor是bean级别的处理,可以拦截到所有bean,调用预处理化postProcessBeforeInitialization方法可以,可以对bean进行预加工
* before方法在自定义iniMethod之前
* 7.
*/
public class Result implements BeanNameAware , BeanFactoryAware , ApplicationContextAware , InitializingBean , DisposableBean {
private String status;
private String message;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "Result{" +
"status='" + status + '\'' +
", message='" + message + '\'' +
'}';
}
public Result() {
System.out.println("1,result 无参构造");
}
@Override
public void setBeanName(String s) {
System.out.println("3,setBeanName,bean的id:"+s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("4,setBeanFactory,管理我的beanfactory为"+beanFactory);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("5,高级接口applicationContext:"+applicationContext);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("7,afterPropertiesSet");
}
public void initMethod(){
System.out.println("8,我是bean的initMethod方法");
}
// 和ini-method 等值可以互换,但还是 有顺序的,优先于7afterPropertiesSet方法执行
@PostConstruct
public void postConstruct(){
System.out.println("postConstruct..");
}
// 注解方式
@PreDestroy
public void mydestroy(){
System.out.println("PreDestroy..");
}
// 销毁方法
@Override
public void destroy() throws Exception {
System.out.println("destroy");
}
public void destroyMethod(){
System.out.println("destroyMethod");
}
/** 1,
* 3,setBeanName,bean的id:result
* 4,setBeanFactory,管理我的beanfactory为org.springframework.beans.factory.support.DefaultListableBeanFactory@76012793: defining beans [accountDao,proxyFactory,transferService,connectionUtils,transactionManager,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,druidDataSource,result,myBeanPostProcessor]; root of factory hierarchy
* 5,高级接口applicationContext:org.springframework.context.support.ClassPathXmlApplicationContext@2d2e5f00: startup date [Tue Mar 03 15:53:56 CST 2020]; root of context hierarchy
* 6,postProcessBeforeInitialization
* postConstruct..
* 7,afterPropertiesSet
* 8,我是bean的initMethod方法
* 9,postProcessAfterInitialization
* result:Result{status='200', message='成功'}
* PreDestroy..
* destroy
* destroyMethod
*
*
*/
}
package com.bigdata.edu.pojo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("result".equalsIgnoreCase(beanName)){
System.out.println("6,postProcessBeforeInitialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("result".equalsIgnoreCase(beanName)){
System.out.println("9,postProcessAfterInitialization");
}
return bean;
}
}
@org.junit.Test
public void testIoc(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// AccountDao accountDao = (AccountDao) classPathXmlApplicationContext.getBean("accountDao");
Result result = (Result) classPathXmlApplicationContext.getBean("result");
System.out.println("result:"+result);
classPathXmlApplicationContext.close();
}
输出结果:
/** 1,result 无参构造
* 3,setBeanName,bean的id:result
* 4,setBeanFactory,管理我的beanfactory为org.springframework.beans.factory.support.DefaultListableBeanFactory@76012793: defining beans [accountDao,proxyFactory,transferService,connectionUtils,transactionManager,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,druidDataSource,result,myBeanPostProcessor]; root of factory hierarchy
* 5,高级接口applicationContext:org.springframework.context.support.ClassPathXmlApplicationContext@2d2e5f00: startup date [Tue Mar 03 15:53:56 CST 2020]; root of context hierarchy
* 6,postProcessBeforeInitialization
* postConstruct..
* 7,afterPropertiesSet
* 8,我是bean的initMethod方法
* 9,postProcessAfterInitialization
* result:Result{status='200', message='成功'}
* PreDestroy..
* destroy
* destroyMethod
*
*
*/