1. Bean scopesjava
Scope用来声明 IoC 容器中对象应该处的限定场景或者说该对象的存活空间,即 IoC 容器在对象进入相应的 scope 以前生成并装配这些对象,在该对象再也不处于 scope 的限定后,容器一般会销毁这些对象。下面是 Scope的分类:web
Scope | Description |
singleton |
(Default) Scopes a single bean definition to a single object instance per spring Spring IoC container.bootstrap |
prototype | Scopes a single bean definition to any number of object instances. |
request | Scopes a single bean definition to the lifecycle of a single HTTP request;session that is, each HTTP request has its own instance of a bean created off the app back of a single bean definition. Only valid in the context of a web-aware ide Spring |
session | Scopes a single bean definition to the lifecycle of an HTTP Only valid in the context of a web-aware Spring |
global session |
Scopes a single bean definition to the lifecycle of a global HTTP Typically only valid when used in a portlet context. Only valid in the context of a web-aware Spring |
application | Scopes a single bean definition to the lifecycle of a in the context of a web-aware Spring |
singleton:单一实例,即一个容器中只存在一个这样的实例,全部对该类型 Bean的依赖都是用这一单一实例 。此外,singleton 类型的 Bean 定义,从容器启动,到它第一次被请求而实例化开始,只要容器不销毁或者退出,该类型 Bean 的单一实例就会一直存活。
prototype:容器在接受到该类型对象的请求时,每次都会从新生成一个新的对象给请求方。但容器将对象实例返回给请求方后,就再也不拥有该对象的引用,请求方须要本身负责当前对象后继生命周期的管理工做。
request、session、global session、application 只适用于 web程序,一般是和 XmlWebApplicationContext 共同使用。
request:Spring 容器,即 XmlWebApplicationContext 会为每一个 HTTP 请求建立一个新的对象,当请求结束后,该对象的生命周期即结束。若是同时又10个 HTTP 请求,容器会分别针对这10个请求建立10个新的对象实例,且实例之间互不干扰。
session:Spring 容器会为每一个独立的 session 建立新的对象实例,比 request scope的 bean存活更长的时间。用户登陆信息通常是用的最多。
global session:只有应用在基于porlet的web应用程序中才有意义,他映射到porlet的global范围的session,若是普通的servlet的web 应用中使用了这个scope,容器会把它做为普通的session的scope对待。
application:暂无。
对于singleton 和 prototype 能够作个实验:
<?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"> <!-- <import resource="beans2.xml"/> --> <bean id="userDAO" class="com.dao.impl.UserDAOImpl" scope="singleton"/> <bean id="userService" class="com.service.impl.UserServiceImpl" scope="prototype"> <property name="userDAO" ref="userDAO" /> </bean> </beans>
测试 Code:
public class UserServiceTest { @Before public void setUp() throws Exception { } @Test public void testAddUser() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserDAOImpl dao1 = (UserDAOImpl) ctx.getBean("userDAO"); UserDAOImpl dao2 = (UserDAOImpl) ctx.getBean("userDAO"); UserServiceImpl service = (UserServiceImpl) ctx.getBean("userService"); UserServiceImpl service2 = (UserServiceImpl) ctx.getBean("userService"); System.out.println(dao1 == dao2); System.out.println(service == service2); } }
结果: true false
2. Bean 建立的时机:
IoC 容器初始化时会预先对非延迟加载的单例对象进行初始化,其余都是在第一次调用 getBean 时被建立。
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons()
public void preInstantiateSingletons() throws BeansException { if (this.logger.isDebugEnabled()) { this.logger.debug("Pre-instantiating singletons in " + this); } // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } // Trigger post-initialization callback for all applicable beans... for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { smartSingleton.afterSingletonsInstantiated(); return null; } }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
3. 延迟初始化 Bean
指在 IoC 容器启动时,并不初始化 延迟初始化的 Bean,而是在使用时才会建立以及初始化 Bean。
配置方式:在 <bean> 标签上指定 lazy-init 属性值为 "true",如: <bean id="xxx" class="xxx" lazy-init="true" />
Spring 容器预先初始化 Bean 一般能帮助咱们提早发现配置错误,因此通常状况下不建议开启lazy-init。除非有某个 Bean 可能须要加载很大资源,并且在整个应用程序生命周期中极可能使用不到,那么能够设置为 延迟初始化。
延迟初始化的 Bean 一般会在第一次使用时被初始化;或者在 被非延迟初始化 Bean 做为依赖对象注入时,随着该 Bean 的初始化而初始化 lazy-init Bean。
4. 自动装配(Autowire)
Autowire 指由 spring 容器自动地注入依赖对象。
Mode | Explanation |
no |
(Default) No autowiring. Bean references must be defined via a Changing the default setting is not recommended for larger deployments, because specifying collaborators explicitly gives greater control and clarity. To some extent, it documents the structure of a system. |
byName | Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name, and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named and uses it to set the property. |
byType | Allows a property to be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens; the property is not set. |
constructor | Analogous to byType, but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised. |
目前 Spring 4.2.2 支持 "no","byName","byType","constructor" 四种自动装配,默认是 "no" 指不支持自动装配的。其中Spring 3.0 开始已经不推荐使用以前版本的 "autodetect" 自动装配,推荐使用 Java 5+支持的(@Autowired)注解方式代替;自动装配的好处是:减小构造器注入和setter注入配置,减小配置文件。
配置方式:经过配置<bean>标签的“autowire”属性来改变自动装配方式
<bean id="userService" class="com.service.impl.UserServiceImpl" autowire="byType"> <!-- <property name="userDAO" ref="userDAO" /> --> </bean>
(1)default:表示使用默认的自动装配,默认的自动装配须要在<beans>标签中使用default-autowire属性指定,其支持“no”、“byName ”、“byType”、“constructor”四种自动装配。
<?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" default-autowire="byName">
(2)no:意思是不支持自动装配,必须明确指定依赖。
(3)byName:经过设置Bean定义属性autowire="byName",意思是根据名字进行自动装配,只能用于setter注入。
<?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"> <!-- <import resource="beans2.xml"/> --> <bean id="userDAO" class="com.dao.impl.UserDAOImpl" > <property name="daoId" value="1"></property> </bean> <bean id="userDAO2" class="com.dao.impl.UserDAOImpl" > <property name="daoId" value="2"></property> </bean> <bean id="userService" class="com.service.impl.UserServiceImpl" autowire="byName"> <!-- <property name="userDAO" ref="userDAO" /> --> </bean> </beans>
public class UserServiceImpl implements UserService { private UserDAO userDAO; public UserDAO getUserDAO() { return userDAO; } public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } //constructor // public UserServiceImpl(UserDAO userDAO) { // super(); // this.userDAO = userDAO; // } @Override public void addUser(User user) { this.userDAO.saveUser(user); } }
根据 byName 自动装配会去找 UserServiceImpl 中的 userDAO 这个name的 Bean,而配置文件中有 userDAO 和 userDAO2 两个,其中装配的是 userDAO。若是 userDAO 这个 Bean没有配置,则会报错。
(4)byType:经过设置Bean定义属性autowire="byType",意思是指根据类型注入,用于setter注入。好比若是指定自动装配方式为“byType”,而 setUserDAO() 方法须要注入 UserDAO 类型数据,则Spring容器将查找 UserDAO 类Bean,若是找到一个则注入该Bean,若是找不到将什么也不注入;若是找到多个Bean将优先注入<bean>标签“primary”属性为 true 的 Bean,不然抛出异常来代表有个多个Bean发现但不知道使用哪一个。
(5)constructor:经过设置 Bean 定义属性autowire="constructor",功能和“byType”功能同样,根据类型注入构造器参数,只是用于构造器注入方式。
5. init-method 和 destroy-method
(1)init-method="init" :指定初始化方法,在构造器注入和setter注入完毕后执行。
(2)destroy-method="destroy":指定销毁方法,只有“singleton”做用域能销毁;“prototype”做用域的必定不能,由于容器不会监控 prototype Bean的死亡,推荐不要和 prototype 一块儿使用;其余做用域不必定能;
<bean id="userService" class="com.service.impl.UserServiceImpl" autowire="byName" init-method="init" destroy-method="destroy"> <!-- <property name="userDAO" ref="userDAO" /> --> </bean>