持续学习&持续更新中…
守破离
【雷丰阳SSM基础】【Spring】【04】bean的生命周期+IoC容器_配置bean—中
bean的生命周期
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("5-postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("8-postProcessAfterInitialization");
return bean;
}
}
public class LifeCycleBean implements ApplicationContextAware, BeanNameAware,
InitializingBean, DisposableBean {
private String name;
public LifeCycleBean() {
System.out.println("1-constructor");
}
public void setName(String name) {
System.out.println("2-setter");
this.name = name;
}
@Override
public void setBeanName(String arg0) {
System.out.println("3-setBeanName");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
System.out.println("4-setApplicationContext");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("6-InitializingBean-afterPropertiesSet");
}
public void myInit() {
System.out.println("7-XML-init");
}
public void ownTask() {
System.out.println("9-该Bean的业务方法...");
}
@Override
public void destroy() throws Exception {
System.out.println("10-Disposable-destroy");
}
public void myDestroy() {
System.out.println("11-XML-destroy");
}
}
<?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 class="programmer.lp.MyBeanPostProcessor"/>
<bean id="bean" class="programmer.lp.bean.LifeCycleBean"
init-method="myInit" destroy-method="myDestroy">
<property name="name" value="lp"></property>
</bean>
</beans>
@Test
public void test() {
ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("lifecycle.xml");
ioc.getBean("bean", LifeCycleBean.class).ownTask();
ioc.close();
}
如果使用纯注解的话:
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("5-postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("8-postProcessAfterInitialization");
return bean;
}
}
@Import(MyBeanPostProcessor.class)
public class LifeCycleBean implements ApplicationContextAware, BeanNameAware,
InitializingBean, DisposableBean {
private String name;
public LifeCycleBean() {
System.out.println("1-constructor");
}
@Value("lpruoyu")
public void setName(String name) {
System.out.println("2-setter");
this.name = name;
}
@Override
public void setBeanName(String arg0) {
System.out.println("3-setBeanName");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
System.out.println("4-setApplicationContext");
}
@PostConstruct
public void annotationInit() {
System.out.println("6-@PostConstruct");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("7-InitializingBean-afterPropertiesSet");
}
public void ownTask() {
System.out.println("9-该Bean的业务方法...");
}
@PreDestroy
public void annotationDestroy() {
System.out.println("10-@PreDestroy");
}
@Override
public void destroy() throws Exception {
System.out.println("11-Disposable-destroy");
}
}
注意1:bean的scope默认是单例的。
注意2:@PostConstruct
、@PreDestroy
是JSR注解,但是在这儿却不用导入相应的jar包。
注意3:使用AnnotationConfigApplicationContext创建IoC容器需要依赖aop包,因此需要将spring-aop-4.0.0.RELEASE.jar
导入项目中。
public static void main(String[] args) {
ConfigurableApplicationContext ioc =
new AnnotationConfigApplicationContext(LifeCycleBean.class);
ioc.getBean("lifeCycleBean", LifeCycleBean.class).ownTask();
ioc.close();
}
实验10:init-method、destroy-method
public class Person {
private String name;
private Integer age;
public void myInit() {
System.out.println("Person - "+ name + " init method");
}
public void myDestroy() {
System.out.println("Person - "+ name + " destroy method");
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
<!--
实验10:创建带有生命周期方法的bean
生命周期:bean的创建到销毁
我们可以为bean自定义一些生命周期方法
,Spring在创建或者销毁bean的时候就会调用这些方法。
IoC容器中创建的bean:
1)、单实例bean:容器启动的时候就会创建好,容器关闭也会被销毁,也就是会调用destroy-method方法
2)、多实例bean:获取的时候才创建,容器关闭不会调用destroy-method方法
自定义初始化、销毁方法:
方法要求:The method must have no arguments, but may throw any exception.
-->
<!-- 单实例bean受IoC容器管理,
在IoC容器启动的时候就会被创建,init-method方法会被调用
在IoC容器close的时候就会调用destroy-method方法 -->
<bean id="xiaoming" class="programmer.lp.bean.Person"
init-method="myInit" destroy-method="myDestroy">
<property name="name" value="lp"/>
<property name="age" value="22"/>
</bean>
<!--
多实例的bean(scope="prototype")
获取(getBean)的时候才被创建,也就是init-method会在创建之后被调用
容器关闭不会调用destroy-method方法
(因为多实例的bean并不属于IoC容器管理、IoC容器只负责创建)
-->
<bean id="xiaohong" class="programmer.lp.bean.Person"
scope="prototype"
init-method="myInit" destroy-method="myDestroy"/>
private final ApplicationContext ctx
= new ClassPathXmlApplicationContext("applicationContext.xml");
@Test
public void test10() {
System.out.println(ctx.getBean("xiaoming"));
// ClassPathXmlApplicationContext c = (ClassPathXmlApplicationContext) ctx;
// IoC容器的close方法在ConfigurableApplicationContext中
ConfigurableApplicationContext c = (ClassPathXmlApplicationContext) ctx;
c.close(); // 关闭某个IoC容器,那些被该IoC容器管理的单实例的bean就会调用destroy-method配置的方法
}
实验11:测试bean的后置处理器
注意:如果Eclipse自动实现的方法的方法参数的参数名是arg0、arg1之类的,那么只需要将源码绑定即可
注意:不管某个bean有没有配置初始化方法,BeanPostProcessor都会默认它有初始化方法,BeanPostProcessor都会工作。也就是说,BeanPostProcessor会接管它所在容器的所有bean的初始化工作;也可以这样说,所有bean都会调用BeanPostProcessor的before、after方法。
// 如果Eclipse自动实现的方法参数的参数名是arg0、arg1之类的,那么只需要将源码绑定即可
public class MyBeanPostProcessor implements BeanPostProcessor {
/*
* bean初始化之前被调用
* 传入的Object bean可以修改一下再返回
* String beanName:给bean配置的id
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println(beanName + "初始化之前被调用");
return bean;
}
/*
* bean初始化之后被调用
* 传入的Object bean可以修改一下再返回
* String beanName:给bean配置的id
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println(beanName + "初始化之后被调用");
// 这一块儿返回的是什么,IoC容器保存的就是什么
return bean;
}
}
<?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">
<!--
实验11:测试bean的后置处理器
后置处理器—BeanPostProcessor:
可以在bean的初始化前后调用其方法。
-->
<!-- 让容器管理该BeanPostProcessor -->
<bean class="programmer.lp.MyBeanPostProcessor"/>
<bean id="xiaoming" class="programmer.lp.bean.Person" init-method="myInit" destroy-method="myDestroy"/>
</beans>
实验12:引用外部属性文件—配置C3P0数据库连接池
db.properties:
user=root
password=root
jdbcUrl=jdbc:mysql://127.0.0.1:3306/test_mybatis
driverClass=com.mysql.jdbc.Driver
applicationContext.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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--
实验12:引用外部属性文件
-->
<!--
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" scope="singleton">
<property name="user" value="root"/>
<property name="password" value="root"/>
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/test_mybatis"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
</bean>
-->
<!-- <context:property-placeholder location="db.properties"/> -->
<!-- SpringMVC中,必须使用classpath:前缀,表示引用类路径下的资源 -->
<context:property-placeholder location="classpath:db.properties"/>
<!--
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" scope="singleton">
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
<property name="jdbcUrl" value="${jdbcUrl}"/>
<property name="driverClass" value="${driverClass}"/>
</bean>
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" scope="singleton"
p:user="${user}"
p:password="${password}"
p:jdbcUrl="${jdbcUrl}"
p:driverClass="${driverClass}"
/>
<!-- username 是计算机的用户名,因此数据库的配置文件中不能使用username -->
<bean class="programmer.lp.bean.Person" p:name="${username}"/>
</beans>
测试:
// 实验12:引用外部属性文件
@Test
public void test12() {
// System.out.println(ctx.getBean(Person.class)); // 测试username
// System.out.println(ctx.getBean("dataSource").hashCode());
// System.out.println(ctx.getBean("dataSource").hashCode());
// System.out.println(ctx.getBean("dataSource").hashCode());
// System.out.println(ctx.getBean(ComboPooledDataSource.class).hashCode());
// System.out.println(ctx.getBean(ComboPooledDataSource.class).hashCode());
// System.out.println(ctx.getBean(ComboPooledDataSource.class).hashCode());
// System.out.println(ctx.getBean(DataSource.class).hashCode());
// System.out.println(ctx.getBean(DataSource.class).hashCode());
// System.out.println(ctx.getBean(DataSource.class).hashCode());
System.out.println(ctx.getBean(DataSource.class) == ctx.getBean("dataSource"));
System.out.println(ctx.getBean(ComboPooledDataSource.class) == ctx.getBean("dataSource"));
System.out.println(ctx.getBean("dataSource", DataSource.class) == ctx.getBean("dataSource"));
}
注意:username
是计算机的用户名,因此数据库的配置文件中不能使用username
这个key。
或者,还可以将db.properties这样写:
jdbc.username=root
jdbc.password=root
jdbc.url=jdbc:mysql://127.0.0.1:3306/test_mybatis
jdbc.driverClassName=com.mysql.jdbc.Driver
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" scope="singleton"
p:user="${jdbc.username}"
p:password="${jdbc.password}"
p:jdbcUrl="${jdbc.url}"
p:driverClass="${jdbc.driverClassName}"
/>
实验13:基于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="car" class="programmer.lp.domain.Car">
<property name="name" value="宝马"/>
<property name="price" value="99.3"/>
</bean>
<!--
使用property为car属性手动赋值
<bean id="xiaoming" class="programmer.lp.domain.Person">
<property name="car" ref="car"/>
</bean>
-->
<!--
为自定义类型自动装配(自动赋值):
autowire="default" : 不自动赋值(装配)
autowire="no" : 不自动赋值(装配)
autowire="byName" : 以属性名作为id,从容器中找组件,为其自动赋值;找不到就装配null
autowire="byType" : 根据属性类型,从容器中找组件,为其自动赋值;
找不到就装配null
如果找到多个(如果容器中有多个这种类型的组件),那么就会出现异常
autowire="constructor" : 按照构造器进行赋值,
public Person(Car car) {
this.car = car;
}
1)按照类型装配
如果没有找到,装配null
如果找到多个,不会报异常,而是到第2)步
2)以属性名作为id装配
如果没有找到,装配null
如果找到了,就装配
优点:不会报错;相当于byName+byType的结合
缺点:需要手动创建构造方法
-->
<!-- 如果该bean有一个List<Book> books属性
那么使用byType自动装配,它会把所有的Book自动装配到一个List中 -->
<bean id="book01" class="programmer.lp.domain.Book" p:name="红楼梦"/>
<bean id="book02" class="programmer.lp.domain.Book" p:name="三国演义"/>
<bean id="book03" class="programmer.lp.domain.Book" p:name="西游记"/>
<bean id="book04" class="programmer.lp.domain.Book" p:name="水浒传"/>
<!-- 相当于: -->
<!--
<util:list id="books">
<bean class="programmer.lp.domain.Book" p:name="红楼梦"/>
<bean class="programmer.lp.domain.Book" p:name="三国演义"/>
<bean class="programmer.lp.domain.Book" p:name="西游记"/>
<bean class="programmer.lp.domain.Book" p:name="水浒传"/>
</util:list>
-->
<bean id="xiaoming" class="programmer.lp.domain.Person"
autowire="constructor">
</bean>
</beans>
实例:
<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<bean id="xiaoming" class="programmer.lp.domain.Human"
autowire="byName"
p:name="张三"
p:age="10"
p:birthday="2000/01/10"/>
<bean id="car" class="programmer.lp.domain.Car">
<property name="name" value="宝马"/>
<property name="price" value="99.3"/>
</bean>
<util:list id="books">
<bean class="programmer.lp.domain.Book" p:name="红楼梦"/>
<bean class="programmer.lp.domain.Book" p:name="三国演义"/>
<bean class="programmer.lp.domain.Book" p:name="西游记"/>
<bean class="programmer.lp.domain.Book" p:name="水浒传"/>
</util:list>
<util:map id="map">
<entry key="language" value="Java"/>
<entry key="core_1" value="DataStructures"/>
<entry key="core_2" value="DesignPattern"/>
<entry key="others">
<bean class="java.lang.Object"/>
</entry>
</util:map>
<util:properties id="properties">
<prop key="jdbc.username">root</prop>
<prop key="jdbc.password">root</prop>
<prop key="jdbc.url">jdbc:mysql://127.0.0.1:3306/test_mybatis</prop>
<prop key="jdbc.driverClassName">com.mysql.jdbc.Driver</prop>
</util:properties>
</beans>
// 实验13:基于XML的自动装配
@Test
public void test13() {
System.out.println(ctx.getBean("xiaoming"));
}
实验14:SpEL(Spring Expression Language)测试
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
实验14:SpEL(Spring Expression Language)测试
使用运算符、
引用其他bean的某个属性值、
引用其他bean、
调用非静态方法、
调用静态方法 :格式:#{T(全类名).方法名(参数)}
-->
<bean id="car" class="programmer.lp.domain.Car">
<property name="name" value="BMW"/>
<property name="price" value="99.3"/>
</bean>
<bean id="model" class="programmer.lp.domain.Model">
<!-- <property name="name" value="lpruoyu"/> -->
<property name="age" value="#{20 + 1}"/>
<property name="name" value="#{car.name}"/>
<property name="birthday" value="#{new java.util.Date()}"/>
<property name="car" value="#{car}"/>
<!-- 调用实例方法 -->
<property name="car.name" value="#{car.getName().substring(0, 1)}"/>
<!-- 调用静态方法 -->
<property name="salary" value="#{T(java.lang.Math).random()}"/>
</bean>
</beans>
注意
-
引用的第三方JAR包应该放在普通目录下
-
项目需要使用的资源文件应该放在资源目录下(
src目录和其它资源目录
下的文件会被编译到项目\bin\
目录中,也就是classpath下)
参考
雷丰阳: 雷神的Spring、Spring MVC、MyBatis课程.
本文完,感谢您的关注支持!