【雷丰阳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课程.


本文完,感谢您的关注支持!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值