Spring5自学笔记_Real002(IOC的Bean管理-基于XML文件)
IOC容器-Bean管理-XML方式
(1)Bean管理主要值得是两个操作:Spring创建对象,Spring注入属性
(2)Bean管理操作有两个方式(基于XML配置文件的方式 和 注解方式)
1)基于XML配置文件方式实现
例子:创建对象,然后注入属性
在编写完Book类之后,设置配置文件如下:
<?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">
<!-- 配置Book对象的创建 -->
<bean id = "User" class = "com.SSMStudy.Spring5.User"></bean>
<!-- 2、set方法注入属性 -->
<bean id = "book" class = "com.SSMStudy.Spring5.testDemo.Book">
<!-- 使用property完成属性的注入
name:类里面属性的名称
value:属性的值-->
<property name="author" value ="余华"></property>
<property name="name" value="活着"></property>
</bean>
</beans>
spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象的创建
在bean标签有很多属性,常用的是id属性:唯一标识,和class属性:类的全路径
属性的注入有两种方式,第一种是用set函数,第二种使用有参构造器进行注入
DI:依赖注入,就是注入属性,DI是IOC的具体实现,他就表示依赖注入,或者说是注入属性,但是他必须在对象创建的基础上进行。
a.set函数注入:然后创建利用Spring创建对象,之后用Set的方式及逆行属性的注入
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Book {
private String name;
private String author;
public void setName(String name) {
this.name = name;
}
public void setAuthor(String author) {
this.author = author;
}
public void print(){
System.out.println(author +":"+name);
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
book.print();
}
}
输出结果:
com.SSMStudy.Spring5.testDemo.Book@79da8dc5
余华:活着
b.通过有参构造器进行属性的注入
创建类,定义属性,创建属性对应的额有参数的构造方法
package com.SSMStudy.Spring5.testDemo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Order {
private String name;
private String address;
//有参数的构造器
public Order(String name, String address) {
this.name = name;
this.address = address;
}
public void print(){
System.out.println(name+":"+address);
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Order order = context.getBean("order", Order.class);
System.out.println(order);
order.print();
}
}
配置文件:
<?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">
<!-- 配置Book对象的创建 -->
<bean id = "User" class = "com.SSMStudy.Spring5.User"></bean>
<!-- 2、set方法注入属性 -->
<bean id="book" class="com.SSMStudy.Spring5.testDemo.Book">
<!-- 使用property完成属性的注入
name:类里面属性的名称
value:属性的值-->
<property name="author" value ="余华"></property>
<property name="name" value="活着"></property>
</bean>
<!-- 3、有参数的构造器注入属性 -->
<bean id="order" class="com.SSMStudy.Spring5.testDemo.Order">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="address" value="中国"></constructor-arg>
</bean>
</beans>
输出结果:
com.SSMStudy.Spring5.testDemo.Order@212b5695
张三:中国
XML属性注入的其他区方式:
字面量:就是值得是属性的初始值
1)空值:null
<constructor-arg name="address">
<null></null>
</constructor-arg>
2)特殊符号:< > (1、使用转移符号或者使用CDATA)
<constructor-arg name="address">
<value><![CDATA[<><>中国南京<><>]]></value>
</constructor-arg>
(3)注入属性-注入外部bean
配置文件:
<!-- 4、注入外部bean(说白了就是在一个类里面调用另一个类) -->
<bean name="userDaoImp" class="com.SSMStudy.Spring5.OutBeanInsert.UserDaoImp"></bean>
<bean id="serviceTest" class="com.SSMStudy.Spring5.OutBeanInsert.ServiceTest">
<property name="userDaoImp" ref="userDaoImp"></property>
</bean>
创建相应的类:ServiceTest调用UserDao类,并调用UserDao的方法print,UserDaoImp接口被UseDaoImp实现
public interface UserDao {
void print();
}
public class UserDaoImp implements UserDao{
@Override
public void print() {
System.out.println("UserDao Start......");
}
}
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ServiceTest {
private UserDao userDaoImp;
public void setUserDaoImp(UserDao userDaoImp) {
this.userDaoImp = userDaoImp;
}
public void print(){
System.out.println("ServiceTest Start......");
userDaoImp.print();
}
@Test
public void testBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
ServiceTest service = context.getBean("serviceTest", ServiceTest.class);
service.print();
}
}
输出结果:
ServiceTest Start......
UserDao Start......
(4)注入属性-注入内部bean
配置文件
与外部注入属性的不同点主要在于XML文件的写法
<!-- 5、内部bean的注入 -->
<bean id="emp" class="com.SSMStudy.Spring5.InsideBean.Emp">
<property name="eName" value="Lucy"></property>
<property name="dept">
<bean id="dept" class="com.SSMStudy.Spring5.InsideBean.Dept">
<property name="DName" value="人事部"></property>
</bean>
</property>
</bean>
创建相应的类:部门类、员工类
public class Dept {
private String dName;
public void setDName(String dName) {
this.dName = dName;
}
@Override
public String toString() {
return "Dept{" +
"dName='" + dName + '\'' +
'}';
}
}
public class Emp {
private String eName;
private Dept dept;
public void seteName(String eName) {
this.eName = eName;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"eName='" + eName + '\'' +
", dept=" + dept +
'}';
}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InsideBeanTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Emp emp = context.getBean("emp", Emp.class);
System.out.println(emp);
}
}
输出结果:
Emp{eName='Lucy', dept=Dept{dName='人事部'}}
(5)注入属性-级联赋值
级联赋值就是在注入外部类属性的时候将bean标签写在外面,然后在类种用ref引入
(第一种形式)
<!-- 6、级联赋值 -->
<bean id="emp" class="com.SSMStudy.Spring5.InsideBean.Emp">
<property name="eName" value="Lucy"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.SSMStudy.Spring5.InsideBean.Dept">
<property name="DName" value="人事部"></property>
</bean>
(第二种形式)(需要在Emp类中生成Dept的Get方法)
<!-- 7、级联赋值第二种形式 -->
<bean id="emp" class="com.SSMStudy.Spring5.InsideBean.Emp">
<property name="eName" value="Lucy"></property>
<property name="dept" ref="dept"></property>
<property name="dept.dName" value="人事部"></property>
</bean>
<bean id="dept" class="com.SSMStudy.Spring5.InsideBean.Dept"></bean>
(6)XML文件注入集合属性-注入数组
创建类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
private String[] strings;
private List<String> list;
private Set<String> set;
private Map<String, String> maps;
public void setStrings(String[] strings) {
this.strings = strings;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void test(){
System.out.println(Arrays.toString(strings));
System.out.println(list);
System.out.println(set);
System.out.println(maps);
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Student stu = context.getBean("stu", Student.class);
stu.test();
}
}
创建配置文件
<!-- 8、集合属性的注入方式 -->
<bean id="stu" class="com.SSMStudy.Spring5.CollectionInsert.Student">
<property name="strings">
<array>
<value>张三</value>
<value>Mary</value>
</array>
</property>
<property name="list">
<list>
<value>Jack</value>
<value>Tom</value>
</list>
</property>
<property name="set">
<set>
<value>Smith</value>
<value>Lucy</value>
</set>
</property>
<property name="maps">
<map>
<entry key="Lucy" value="USA"></entry>
<entry key="Tom" value="Japan"></entry>
</map>
</property>
</bean>
输出结果:
[张三, Mary]
[Jack, Tom]
[Smith, Lucy]
{Lucy=USA, Tom=Japan}
(7)bean管理小结:
Spring中有两种bean管理方式:一个是普通bean管理,另一个使factoryBean管理
两者的区别主要在于:普通Bean管理,在配置文件中定义的Bean类型和返回的类型必须一致,而FactoryBean管理的在配置文件中定义的Bean类型可以和返回类型不一样。
工厂Bean管理:
第一步:创建类,让这个类实现FactoryBean接口
第二步:实现接口里面的方法,在实现的方法中定义
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="myBean" class="com.SSMStudy.Spring5.FactoryBeanStudy.MyBean"></bean>
</beans>
Java程序:
import com.SSMStudy.Spring5.testDemo.Book;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyBean implements FactoryBean<Book> {
/**
* 定义返回的Bean
* @return 要实例化的对象
* @throws Exception
*/
@Override
public Book getObject() throws Exception {
Book book = new Book();
book.setName("三国演义");
book.setAuthor("罗贯中");
return book;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Book book = context.getBean("myBean", Book.class);
System.out.println(book);
}
}
在默认情况下,Bean管理产生的实例是单实例,即获得的所有实例都是同一个,也就是地址是相同的。
(8)如何设置是多实例还是单实例?
在XML配置文件中的Bean标签下有一个属性叫做:scope
将属性设置为singleton或者不写,也就是默认值,那么产生的实例就是单实例,
将属性设置为prototype,则产生的实例是多实例
(9)Bean的生命周期**从对象创建到对象销毁的过程
(1)通过构造器创建Bean实例(无参构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
(3)调用bean的初始化方法(需要进行配置初始化的方法)
(4)bean可以使用了(对象获取到了)
(5)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)
XML配置文件
<bean id="myBeanTest" class="com.SSMStudy.Spring5.FactoryBeanStudy.MyBeanTest" init-method="InitMethod" destroy-method="Destroy">
<property name="name" value="Mary"></property>
<property name="age" value="21"></property>
</bean>
Java程序
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyBeanTest {
private String name;
private int age;
public MyBeanTest() {
System.out.println("一、构造器创建bean实例(无参构造)");
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "MyBeanTest{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void InitMethod(){
System.out.println("三、调用bean的初始化方法");
}
public void Destroy(){
System.out.println("五、调用bean的销毁方法");
}
@Test
public void ApplicationContextTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
//System.out.println("二、调用set方法,设置了属性值");
MyBeanTest myBeanTest = context.getBean("myBeanTest", MyBeanTest.class);
System.out.println("四、获取到了MyBeanTest的对象");
System.out.println(myBeanTest);
((ClassPathXmlApplicationContext)context).close();
}
}
输出结果:
一、构造器创建bean实例(无参构造)
一、构造器创建bean实例(无参构造)
三、调用bean的初始化方法
四、获取到了MyBeanTest的对象
MyBeanTest{name='Mary', age=21}
五、调用bean的销毁方法
**注意:**如果加入例如Bean的后置管理器,则会多处两步,一共七步
(1)通过构造器创建Bean实例(无参构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
(3)把bean的实例添加到bean 的后置处理器中
(4)调用bean的初始化方法(需要进行配置初始化的方法)
(5)把bean的实例添加到bean 的后置处理器中
(6)bean可以使用了(对象获取到了)
(7)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)
完整流程:
(1)首先创建类,实现接口BeanPostProcesser创建后置处理器
(2)实现两个方法,这两个方法对应了上述第3步和第5步的两个过程
(3)在配置文件中加入bean标签用于MyBeanPost后置处理器类的创建
<bean id="myBeanPost" class="com.SSMStudy.Spring5.FactoryBeanStudy.MyBeanPost"></bean>
MyBeanPost类的编写
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
我们将上面的例子重新运行,得到结果:
一、构造器创建bean实例(无参构造)
一、构造器创建bean实例(无参构造)
在初始化之前执行
三、调用bean的初始化方法
在初始化之后执行
四、获取到了MyBeanTest的对象
MyBeanTest{name='Mary', age=21}
五、调用bean的销毁方法
(10)Bean管理的自动装配
根据指定装配规则(根据属性名称或者属性类型),Spring自动将匹配的属性值进行注入
演示:
<!-- 实现自动装配
bean标签属性autowire,配置自动装配
byName根据属性名称进行注入,注入值bean的id值必须和类属性名曾一样
byType根据属性类型注入
-->
<bean id="emp" class="com.SSMStudy.Spring5.FactoryBeanStudy.Emp1" autowire="byName"></bean>
<bean id="dept" class="com.SSMStudy.Spring5.FactoryBeanStudy.Dept1">
<property name="dName" value="人事部"></property>
</bean>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyBeanAutoWire {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Emp1 emp = context.getBean("emp", Emp1.class);
System.out.println(emp);
}
}
class Emp1{
private Dept1 dept;
public void setDept(Dept1 dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp1{" +
"dept=" + dept +
'}';
}
}
class Dept1{
private String dName;
public void setdName(String dName) {
this.dName = dName;
}
@Override
public String toString() {
return "Dept1{" +
"dName='" + dName + '\'' +
'}';
}
}
(11)操作Bean管理(引入外部属性文件)
演示:配置数据库连接的基础信息
第一种方式 直接配置数据库信息
(1)下载德鲁伊jar包
https://repo1.maven.org/maven2/com/alibaba/druid/
(2)引入德鲁伊jar包
(3)配置德鲁伊连接池
<!-- 直接配置连接池 -->
<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="000000"></property>
</bean>
</beans>
第二种方式 引入外部的属性文件
首先创建jdbc.properties属性文件
(2)把外部的jdbc.properties文件引入到Spring配置文件种
<?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"
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">
<!-- 外部引入属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置连接池 -->
<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>
</beans>