两种bean
Spring中有两种bean:一种普通bean,另外一种工厂bin (Factory Bin,注意不是前面说的BeanFactory类)
普通Bean:xml中定义什么类型返回的就是什么类型
<bean id="book" class="com.i7i8i9.spring5.collectiontype.Book">
xml中class是Book, 返回的也是Book
public void testBooks(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean2.xml");
Book book=context.getBean("book", Book.class);
book.test();
}
工厂Bean: 定义和返回可以不一样
1)创建一个类,实现一个接口,作为工厂类,规定返回泛型
<bean id="myBean" class="com.i7i8i9.spring5.collectiontype.factorybean.MyBean">
public class MyBean implements FactoryBean<Courses> { @Override //定义返回对象类型, public Courses getObject() throws Exception { Courses courses=new Courses(); courses.setcNames("化学"); return courses; }
2)测试
@Test public void testMyBean() { ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml"); //MyBean没有继承 FactoryBean<Courses>前 // MyBean myBean= context.getBean("myBean", MyBean.class); Courses myBean= context.getBean("myBean", Courses.class); System.out.println(myBean); }
Bean作用域
在spring里面可以设置创建Bean实例是单实例还是多实例,默认单实例
默认看
生成的两个对象地址一样,就是单实例
在XML bean标签可以增加配置
<!-- 注入-->
<!-- <bean id="book" class="com.i7i8i9.spring5.collectiontype.Book" scope="singleton">-->
<!-- 多实例-->
<bean id="book" class="com.i7i8i9.spring5.collectiontype.Book" scope="prototype">
<property name="list" ref="bookList">
</property>
</bean>
不写scope,默认singleton
如果写了prototype,则可以看到,生成了多个地址的对象 ,但是不是在加载spring配置文件时创建,而是在调用getBean方法时创建多实例对象
scope还有 request 和 session
request:一次请求 把创建对象放到request
session:会话 把创建对象放到session
Bean生命周期--7步
1)创建:通过构造器创建Bean实例(无参);------xml
2) 为Bean属性设置值和对其他Bin引用(调用了set方法)----xml
3)调用Bean的初始化方法-需要进行配置
4)Bean可以使用了,对象实例已经获取到
5)当容器关闭,调用Bean的销毁方法-需要配置
类修改为,明文写出无参构造函数,自己建立初始化方法,和销毁方法,两个方法随便命名
public class Orders {
private String oName;
public Orders() {
System.out.println("第一步,无参构造");
}
public void setoName(String oName) {
this.oName = oName;
System.out.println("第二部,调用Set方法设置属性值");
}
//创建初始化执行方法
public void initOrders(){
System.out.println("第三步,执行初始化方法");
}
//创建销毁执行方法
public void destroyOrders(){
System.out.println("第五步,执行销毁方法");
}
}
将初始化和销毁方法配置到xml,就是给Bean增加两个参数
<bean id="orders" class="com.i7i8i9.spring5.collectiontype.bean.Orders" init-method="initOrders" destroy-method="destroyOrders">
<property name="oName" value="电器">
</property>
</bean>
因为不会自动调用销毁方法,所以修改测试类进行手动销毁
public void testOrders(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
Orders orders= context.getBean("orders", Orders.class);
System.out.println("第四步骤:获取Bean实例");
System.out.println(orders);
//手动执行销毁 ApplicationContext是抽象类,本身没有销毁方法,其调用ClassPathXmlApplicationContext的销毁方法
((ClassPathXmlApplicationContext)context).close();
}
除了以上五步,Bean还有后置处理器,在初始化前后
1)创建:通过构造器创建Bean实例(无参);------xml
2) 为Bean属性设置值和对其他Bin引用(调用了set方法)----xml
3.1)初始化前,把Bean实例传递给后置处理器
BeanPostProcessor接口的方法 postProcessBeforeInitialization
3.2)调用Bean的初始化方法-需要进行配置
3.3)初始化后,把Bean实例传递给后置处理器
BeanPostProcessor接口的方法 postProcessAfterInitialization
4)Bean可以使用了,对象实例已经获取到
5)当容器关闭,调用Bean的销毁方法-需要配置
举例:
1)需要额外建立一个类,实现后置处理器
public class MyBeanPost implements BeanPostProcessor {
//从BeanPostProcessor接口中复制两个方法过来,把default改成public
//@Nullable改成 @Override
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3.1初始化之前的方法");
return bean;
}
//@Nullable改成 @Override
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3.3初始化之后的方法");
return bean;
}
}
修改XML增加上面的Bean
<bean id="orders" class="com.i7i8i9.spring5.collectiontype.bean.Orders" init-method="initOrders" destroy-method="destroyOrders">
<property name="oName" value="电器">
</property>
</bean>
<!-- 配置后置处理器-->
<bean id="myBeanPost" class="com.i7i8i9.spring5.collectiontype.bean.MyBeanPost"></bean>
这样该XML中所有Bean都有了后置处理器,测试文件没怎么修改,如下
@Test
public void testOrders(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
Orders orders= context.getBean("orders", Orders.class);
System.out.println("第四步骤:获取Bean实例");
System.out.println(orders);
//手动执行销毁 ApplicationContext是抽象类,本身没有销毁方法,其调用ClassPathXmlApplicationContext的销毁方法
((ClassPathXmlApplicationContext)context).close();
}
}
输出:
第一步,无参构造
第二部,调用Set方法设置属性值
3.1初始化之前的方法
第三步,执行初始化方法
3.3初始化之后的方法
第四步骤:获取Bean实例
com.i7i8i9.spring5.collectiontype.bean.Orders@6b695b06
第五步,执行销毁方法
Process finished with exit code 0
自动装配
xml中手动设置property叫手动装配
根据指定装配规则(属性名称或属性类型),Spring将自动匹配的属性值进行注入,不需要写property标签
第一种 byName: xml中bean的id要和类中的属性名称要一致
1)xml中增加autowire="byName"
2)类中属性名为department,xml中ref="department",同时Bean的id 也有department
xml:
<bean id="employee" class="com.i7i8i9.spring5.autowire.Employee" autowire="byName">
<!-- <property name="department" ref="department"> </property>-->
<!-- 实现自动装配-->
</bean>
类中
public class Employee {
private Department department;
public void setDepartment(Department department) {
this.department = department;
}
@Override
public String toString() {
return "Employee{" +
"department=" + department +
'}';
}
public void test(){
System.out.println(department);
}
}
第二种根据类型自动装配
<bean id="employee" class="com.i7i8i9.spring5.autowire.Employee" autowire="byType">
上文中根据类型就是在Employee类中有个属性的类型是
public class Employee {
private Department department;
属性类型是Department,那么就会去xml中找到class是Department的bean
注意这个时候同一个类不能有多个Bean,否则还是要用byName
<bean id="department" class="com.i7i8i9.spring5.autowire.Department">
测试输出
Employee{department=Department{}}
补充Deapartment类
public class Department {
@Override
public String toString() {
return "Department{}";
}
}
补充Employee类
package com.i7i8i9.spring5.autowire;
public class Employee {
private Department department;
public void setDepartment(Department department) {
this.department = department;
}
@Override
public String toString() {
return "Employee{" +
"department=" + department +
'}';
}
public void test(){
System.out.println(department);
}
}
补充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="employee" class="com.i7i8i9.spring5.autowire.Employee" autowire="byName">-->
<!-- <property name="department" ref="department"> </property>-->
<!-- 实现自动装配-->
<bean id="employee" class="com.i7i8i9.spring5.autowire.Employee" autowire="byType">
</bean>
<bean id="department" class="com.i7i8i9.spring5.autowire.Department">
</bean>
</beans>
如果不配autowire则会输出:
Employee{department=null}
IOC操作Bean-引入外部属性文件
以数据库连接池为例
引入jar包:Central Repository: com/alibaba/druidf
复制到lib
引入
1)配置XML Bean:直接配置
就是明文写value内容的意思
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
2)引入外部properties文件
src下创建文件
在里面写,左边属性名是自定义的,为了防止冲突都用了prop.开头
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/musicbird
prop.username=root
prop.password=123456
引入spring配置文件:
之前学过引入p空间用来定义属性,util空间 用来把多值的集合提取出来成为公共集合
这次定义引入context名称空间
同样增加一行xmlns,另外xsi中增加两个http,用context替换了三处beans
<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 http://www.springframework.org/schema/context/spring-context.xsd">
使用新标签
<!-- 引入外部属性文件 jdbc.properties在src下,所以直接写出-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>