Spring5----复习笔记2
今天的笔记总结还是基于配置文件进行对象属性注入,不过注入的是类型为数组,集合,map的注入。
一、IOC操作Bean管理(xml注入集合属性):
Student类型:
public class Student { //1.数组类型属性 private String[] courses; //2.list集合类型属性 private List<String> list; //3.map集合类型属性 private Map<String,String> maps; //4.set集合类型属性 private Set<String> set; //学生所学多门课程 private List<Course> courseList; public void setCourseList(List<Course> courseList) { this.courseList = courseList; } public void setSet(Set<String> set) { this.set = set; } public void setCourses(String[] courses) { this.courses = courses; } public void setList(List<String> list) { this.list = list; } public void setMaps(Map<String, String> maps) { this.maps = maps; } @Override public String toString() { return "Student{" + "courses=" + Arrays.toString(courses) + ", list=" + list + ", maps=" + maps + ", set=" + set + ", courseList=" + courseList + '}'; } }
Course类型:
public class Course { private String cname; public void setCname(String cname) { this.cname = cname; } @Override public String toString() { return "Course{" + "cname='" + cname + '\'' + '}'; } }
利用property实现属性的注入:
bean1.xml:
<!--1 集合类型属性--> <bean id="stu" class="com.learn.bean.Student"> <!--数组类型属性注入--> <property name="courses"> <array> <value>java课程</value> <value>数据库课程</value> </array> </property> <!--list集合类型属性注入--> <property name="list"> <list> <value>张三</value> <value>李四</value> </list> </property> <!--map集合类型属性注入--> <property name="maps"> <map> <entry key="key1" value="value1" > </entry> <entry key="key2" value="value2" > </entry> </map> </property> <!--set集合属性注入--> <property name="set"> <set> <value>MySQL</value> <value>Redis</value> </set> </property> <!--注入list集合类型,值是对象--> <property name="courseList"> <list> <ref bean="course1" /> <ref bean="course2" /> </list> </property> </bean> <!--创建多个course对象--> <bean class="com.learn.bean.Course" id="course1"> <property name="cname" value="Spring5框架"> </property> </bean> <bean class="com.learn.bean.Course" id="course2"> <property name="cname" value="Mybatis框架"> </property> </bean>
可以看到我们在注入数组属性时要用Array标签,并且内部属性用value标签。list属性就用list属性,内部属性也用value。map属性用map标签,内部对象要用entry标签,entry标签属性有key和value属性。set属性用set标签,内部用value属性。
java程序:
@Test public void testStuCollection() { ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); Student stu = context.getBean("stu", Student.class); System.out.println(stu); }
控制台输出:
Student{courses=[java课程, 数据库课程], list=[张三, 李四], maps={key1=value1, key2=value2}, set=[MySQL, Redis], courseList=[Course{cname='Spring5框架'}, Course{cname='Mybatis框架'}]}
二、提取注入的集合部分
Book对象:
public class Book { private List<String> list; public void setList(List<String> list) { this.list = list; } @Override public String toString() { return "Book{" + "list=" + list + '}'; } }
bean2.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: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.xsd"> <!--1 提取list集合类型属性注入--> <util:list id="bookList"> <value>深入理解jvm</value> <value>大话设计模式</value> <value>计算机网络自顶向下</value> </util:list> <!--2 提取后注入使用--> <bean class="com.learn.bean.Book" name="book1" scope="prototype"> <property name="list" ref="bookList"> </property> </bean> </beans>
首先我们要注意引入util名称空间,并且在schemaLocation配置相应的地址。
我这里就不演示了,不过注意一点,我在bean的这里的这个属性:
scope="prototype"
这里是来控制这个对象是采用单例模式还是多例模式。
scope属性:singleton 单实例
prototype 多实例
singleton和prototype区别:
① singleton表示单实例,prototype表示多实例
② 设置scope是单实例时,加载spring配置文件的时候就会创建
设置scope是多实例时,不是在加载spring配置文件时创建对象,在调用getBean()方法时创建多实例对象
比如我在这里的xml文件中就配置了多例模式,那么如果我在程序中创建了两个book对象出来的话使用==号判断他们是不是同一个对象,那么就应该输出false
@Test public void testBookColletion() { ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml"); Book book1 = context.getBean("book1", Book.class); Book book2 = context.getBean("book1", Book.class); System.out.println(book1 ==book2); }
输出:
false
三、xml配置文件生成的bean的生命周期
bean生命周期 (1) 通过构造器创建bean实例(无参) (2) 为 bean的属性设置值 和 其他bean引用(set方法) (3) 调用bean的初始化方法(需要进行配置) (4) bean就可以使用了 (对象获取到了) (5) 当容器关闭,调用bean的销毁方法
如果我们想要直观的看到的话就需要在bean类中配置方法:
public class Orders { private String oname; public void setOname(String oname) { this.oname = oname; System.out.println("第二步 调用set方法设置属性的值"); } public Orders() { System.out.println("第一步 执行无参构造"); } //创建执行的初始化方法 public void initMethod() { System.out.println("第三步 执行初始化方法"); } //执行销毁的方法 public void destroy() { System.out.println("第五步 销毁对象"); } }
注意这里的名字一定要是对应的。
同时我们也可以配置bean的后置处理器:
bean的后置处理器(7步)
(1) 通过构造器创建bean实例(无参) (2) 为 bean的属性设置值 和 其他bean引用(set方法) (3) 把bean的实例传递给bean后置处理器的方法 postProcessBeforeInitialization() (4) 调用bean的初始化方法(需要进行配置) (5) 把bean实例传递给bean后置处理器的方法 postProcessAfterInitialization() (6) bean就可以使用了 (对象获取到了) (7) 当容器关闭,调用bean的销毁方法
这里的后置处理器也是之前5步生命周期的扩充,我们也要写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); } }
并且需要在xml配置文件中配置:
<bean id="orders" class="com.learn.bean.Orders" init-method="initMethod" destroy-method="destroy"> <property name="oname" value="手机"/> </bean> <bean id="myBeanPost" class="com.learn.bean.MyBeanPost"> </bean>
java程序:
@Test public void testLife() { ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); Orders orders = context.getBean("orders", Orders.class); System.out.println("第四步,获取实例"); System.out.println(orders); ((ClassPathXmlApplicationContext) context).close(); }
这里要注意,因为在Application接口中没有close方法,所以需要强转一下再调用close方法,容器关闭后bean对象就被销毁了。
输出:
第一步 执行无参构造
第二步 调用set方法设置属性的值
在初始化之前执行的方法
第三步 执行初始化方法
在初始化之后执行的方法
第四步,获取实例
com.learn.bean.Orders@6ec8211c
第五步 销毁对象
四、xml自动装配
在web.xml中使用autowire实现自动装配(也就是不用写property标签了,不过这种方法不常用,写property给人的感觉更自然更好懂)
Emp对象:
public class Emp { private Dept dept; public void setDept(Dept dept) { this.dept = dept; } @Override public String toString() { return "Emp{" + "dept=" + dept + '}'; } }
Emp中的属性Dept类:
public class Dept { @Override public String toString() { return "Dept{}"; } }
bean.xml中的配置:
<!-- 实现自动装配 bean标签中属性:autowire属性常用两个值: byName根据属性名称注入 byType根据属性类型 id值和名称相同 --> <bean id="emp" class="com.learn.autoWire.Emp" autowire="byName"> <!-- <property name="dept" ref="dept"> </property>--> </bean> <bean id="dept" class="com.learn.autoWire.Dept"> </bean>
这里我把property标签注释掉了,但是Dept还是注入对象中了。
java程序:
@Test public void testAutoWire() { ApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml"); Emp course = context.getBean("emp", Emp.class); System.out.println(course); }
运行结果:
Emp{dept=Dept{}}
五、xml配置文件实现引入外部文件
druid.properties文件配置:
username=root password=root url=jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=utf8 driverClassName=com.mysql.jdbc.Driver initialSize=5 maxActive=10
在bean.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" 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:druid.properties" /> <!--直接配置连接池--> <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/test"></property>--> <!-- <property name="username" value="root"></property>--> <!-- <property name="password" value="root"></property>--> <property name="driverClassName" value="${driverClassName}"> </property> <property name="url" value="url"> </property> <property name="username" value="username"> </property> <property name="password" value="password"> </property> </bean> </beans>
这里也需要引入名称空间context实现外部文件的引入
引入时的location中一定要加上classpath:字段,就能匹配到当前src文件下的位置了。
在property中引入外部对象需要使用 ${文件中的键} 表达式
不过用德鲁伊的话最好还是老老实实自己手写,不要引入外部文件,之前我在写JDBC的时候就出现配置文件无法实现而导致必须连接无法建立的这种尴尬局面。