Spring学习笔记(二)
续Spring 学习笔记(一)之后,对Spring框架XML的操作进行整理
1 什么是IOC(DI)
IOC = inversion of control 控制反转
DI = dependency injection 依赖注入
2 个人理解IOC(DI)的好处和作用
本来自己在代码NEW的东西改为由Spring来管理,体现了控制方的转变。
在由Spring管理的时候,需要用户通过配置bean来实现bean与bean的关联,依赖/注入为配置的方式,
好处何作用---》只需要管理配置文件就可以对类的进行管理-->灵活,可阅读性强。
本次笔记中的Spring的常用配置说明目录
1 Spring的注入类型
2 简单的属性注入
3 scope属性
4 集合注入MAP,SET,LIST
5 自动装配 autowire
6 生命周期lazy-init 和初始毁灭方法的调用 init-method,destroy-method
3 Spring 的注入类型
a setter注入(笔记一里已经实现,不再累述)
b 构造方法注入(沿用笔记一里的文件进行修改)
UserServiceImpl 类(存在构造函数)
package com.serviceImpl; import com.dao.UserDao; import com.daoImpl.UserDaoImpl; import com.entity.User; public class UserServiceImpl { private UserDao userDao; UserServiceImpl(UserDao userDao){//构造函数 this.userDao = userDao; } public void add(User user) { userDao.save(user); } public void modify(User user) { userDao.update(user); } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
beans.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="userDaoImpl" class="com.daoImpl.UserDaoImpl"> </bean> <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2"> </bean> <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl"> <constructor-arg><ref bean="userDaoImpl"/></constructor-arg> <!-- 构造函数的注入配置--> </bean> </beans>
执行UserServiceImplTest文件(无任何改动)
执行结果
testName-->testRemark save --调用UserDaoImpl!
testName-->testRemark update --调用UserDaoImpl!
总结,构造方法与setter方法注入实现起来差不多,只是调用的bean里面内部的标签不同而已
4 bean 标签里 使用Id和name的区别,这个不做研究了,查看了下文档,name只可以输入特殊字符"@#!@$!",没什么区别。
4 简单的属性注入
UserServiceImpl里面有个int类型的变量testInjectValue 未赋值
package com.serviceImpl; import com.dao.UserDao; import com.daoImpl.UserDaoImpl; import com.entity.User; public class UserServiceImpl { private UserDao userDao; int testInjectValue;//简单属性注入的测试 UserServiceImpl(UserDao userDao){ this.userDao = userDao; } public void add(User user) { userDao.save(user); System.out.println("testInjectValue = "+testInjectValue); } public void modify(User user) { userDao.update(user); System.out.println("testInjectValue = "+testInjectValue); } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } public int getTestInjectValue() { return testInjectValue; } public void setTestInjectValue(int testInjectValue) { this.testInjectValue = testInjectValue; } }
我们通过beans.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="userDaoImpl" class="com.daoImpl.UserDaoImpl"> </bean> <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2"> </bean> <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl"> <constructor-arg><ref bean="userDaoImpl"/></constructor-arg> <property name="testInjectValue" value="34"></property> <!--简单属性的注入--> </bean> </beans>
执行测试文件
执行结果
testName-->testRemark save --调用UserDaoImpl!
testInjectValue = 34
testName-->testRemark update --调用UserDaoImpl!
testInjectValue = 34
总结.与接口的setter注入差不多,只是接口对应的是 bean="beanName", 这里是value="value"
5 bean里面的scope属性的运用
1 scope=singleton
beans.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="userDaoImpl" class="com.daoImpl.UserDaoImpl"> </bean> <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2"> </bean> <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl" scope="singleton"> <!-- 添加配置scope="singleton"--> <constructor-arg><ref bean="userDaoImpl"/></constructor-arg> </bean> </beans>
2 scope=prototype
beans.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="userDaoImpl" class="com.daoImpl.UserDaoImpl"> </bean> <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2"> </bean> <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl" scope="prototype"> <!-- 添加配置scope="prototype"--> <constructor-arg><ref bean="userDaoImpl"/></constructor-arg> </bean> </beans>
3 分别配置scope=prototype/singleton和不配置scope 并执行UserServiceImplTest文件并查看结果
package com.serviceImpl.test; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.entity.User; import com.serviceImpl.UserServiceImpl; public class UserServiceImplTest { User user; @Before public void setUp() throws Exception { user = new User(); user.setName("testName"); user.setRemark("testRemark"); } @Test public void testAdd() { ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl"); UserServiceImpl UserServiceImpl2 = (UserServiceImpl)app.getBean("userServiceImpl"); System.out.println(UserServiceImpl==UserServiceImpl2); // UserServiceImpl.add(user);//调用方法 } @Test public void testModify() { ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl"); UserServiceImpl UserServiceImpl2 = (UserServiceImpl)app.getBean("userServiceImpl"); System.out.print(UserServiceImpl==UserServiceImpl2); // UserServiceImpl.modify(user); } }
当scope=singleton时 执行结果为 true true
当scope=prototype时 执行结果为false false
当不配置scope时 执行结果为true true
总结 scope不做定义时,spring默认类的实现方式是为单例模式
只有scope=prototype时,spring会在每次调用时都去重新NEW一个新的类
6集合注入
UserServiceImpl
package com.serviceImpl; import java.util.List; import java.util.Map; import java.util.Set; import com.dao.UserDao; import com.daoImpl.UserDaoImpl; import com.entity.User; public class UserServiceImpl { private UserDao userDao; Map testMap; Set testSet; List testList; public void add(User user) { userDao.save(user); System.out.println(testMap.get("m")); System.out.println(testSet.iterator()); System.out.println(testList.get(0)); } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } public Map getTestMap() { return testMap; } public void setTestMap(Map testMap) { this.testMap = testMap; } public Set getTestSet() { return testSet; } public void setTestSet(Set testSet) { this.testSet = testSet; } public List getTestList() { return testList; } public void setTestList(List testList) { this.testList = testList; } }
beans.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="userDaoImpl" class="com.daoImpl.UserDaoImpl"> </bean> <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2"> </bean> <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl"> <property name="userDao" ref="userDaoImpl"></property> <property name="testList"> <list> <value>inject list</value> </list> </property> <property name="testMap"> <map> <entry key="m" value="inject map" /> </map> </property> <property name="testSet"> <set> <value>inject set</value> </set> </property> </bean> </beans>
执行UserServiceImplTest文件
执行结果
testName-->testRemark save --调用UserDaoImpl!
inject map
java.util.LinkedHashMap$KeyIterator@435a3a
inject list
总结
1 这个还是和之前的注入差不多,要用的时候看一眼说明书即可。
7 自动装配(不是很常用)
autowire="byName"(不在代码实现了,用byType抛砖引玉)
autowire="byType"(注意:spring如果找到一个以上的具有同类型的bean会报错,所以我这里注释了userDaoImpl的bean)
beans.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="userDaoImpl" class="com.daoImpl.UserDaoImpl">--> <!-- </bean>--> <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2"> </bean> <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl" autowire="byType"> <!-- <property name="userDao" ref="userDaoImpl"></property>--> </bean> </beans>
执行UserServiceImplTest文件
执行结果
testName-->testRemark save --调用UserDaoImpl2!
总结
1 这个功能点不是很重要,按类型的话很多bean可能会起冲突,如果按名字的话,又对名字有很高的匹配要求,所以不是很实用。
2 另外在头部配置 autowire 的默认值后,可以使用beans的属性:default-autowire (基于这个功能不是很实用,所以没去试过)。
8 生命周期(配置bean的初始策略)
lazy-init
当不配置lazy-init=true时 applicationcontext被NEW出来的时候,所有的bean都会被初始化。
当配置了,这个bean就不会被初始化,除非方法调用。(系统启动特别慢时,可以考虑lazy-init =true 不然没什么太大意义)
init-method destroy-methd 方法的使用
beans.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="userDaoImpl" class="com.daoImpl.UserDaoImpl"> </bean> <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2"> </bean> <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl" init-method="init" destroy-method="destroy" lazy-init="true"> <property name="userDao" ref="userDaoImpl"></property> </bean> </beans>
UserServiceImpl
package com.serviceImpl; import com.dao.UserDao; import com.daoImpl.UserDaoImpl; import com.entity.User; public class UserServiceImpl { private UserDao userDao; public void add(User user) { userDao.save(user); } public void init(){//初始方法 System.out.println("init"); } public void destroy(){//销毁方法 System.out.println("destory"); } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
UserServiceImplTest
package com.serviceImpl.test; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.entity.User; import com.serviceImpl.UserServiceImpl; public class UserServiceImplTest { User user; @Before public void setUp() throws Exception { user = new User(); user.setName("testName"); user.setRemark("testRemark"); } @Test public void testAdd() { ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl"); UserServiceImpl UserServiceImpl1 = (UserServiceImpl)app.getBean("userServiceImpl"); UserServiceImpl.add(user);//调用方法 app.destroy();//在WEB应用里会自动调用,这里直接手动调用了。 } }
执行UserServiceImplTest文件
执行结果
init
testName-->testRemark save --调用UserDaoImpl!
destory
总结
init-method destroy-methd 方法的使用需要注意别与scope=prototype并用,用上面的代码测试了一下,结果是init被调用了2次,但是destroy未被调用过,不解。
结束总结
Spring配置文件提供了以下的配置手法及管理策略,对项目的管理能有不少的帮助,学习下来较为实用的还是setter注入。
1 Spring的注入类型
2 简单的属性注入
3 scope属性
4 集合注入MAP,SET,LIST
5 自动装配 autowire
6 生命周期lazy-init 和初始毁灭方法的调用 init-method,destroy-method