赞
踩
Spring开发中主要是对Bean的配置,Bean的常用配置一览如下:
例如:配置UserDaoImpl由Spring容器负责管理
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
此时存储到Spring容器(singleObjects单例池)中的Bean的beanName是userDao,值是UserDaoImpl对象,可以根据beanName获取Bean实例
applicationContext.getBean("userDao");
如果有不配置id,则Spring会把当前Bean实例的全限定名作为beanName
applicationContext.getBean("com.itheima.dao.impl.UserDaoImpl");
可以为当前Bean指定多个别名,根据别名也可以获得Bean对象
<bean id="userDao" name="aaa,bbb" class="com.itheima.dao.impl.UserDaoImpl"/>
此时多个名称都可以获得UserDaoImpl实例对象
- applicationContext.getBean("userDao");
- applicationContext.getBean("aaa");
- applicationContext.getBean("bbb");
默认情况下,单纯的Spring环境Bean的作用范围有两个:Singleton和Prototype
当Scope设置为singleton时,获得两次对象打印结果是一样的
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="singleton"/>
-
- Object userDao = applicationContext.getBean("userDao");
- Object userDao2 = applicationContext.getBean("userDao");
- System.out.println(userDao); //com.itheima.dao.impl.UserDaoImpl@631330c
- System.out.println(userDao2); //com.itheima.dao.impl.UserDaoImpl@631330c
通过断点调试,观察可以发现单例池中存在userDao实例
当scope设置为prototype时,获得两次对象打印结果是不一样的**
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="prototype"/>
-
- Object userDao = applicationContext.getBean("userDao");
- Object userDao2 = applicationContext.getBean("userDao");
- System.out.println(userDao); //com.itheima.dao.impl.UserDaoImpl@4d50efb8
- System.out.println(userDao2); //com.itheima.dao.impl.UserDaoImpl@7e2d773b
当lazy-init设置为true时为延迟加载,也就是当Spring容器创建的时候,不会立即创建Bean实例,等待用到时在创建Bean实例并存储到单例池中去,后续在使用该Bean直接从单例池获取即可,本质上该Bean还是单利的。
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" lazy-init="true"/>
Bean在被实例化后,可以执行指定的初始化方法完成一些初始化的操作,Bean在销毁之前也可以执行指定的销毁方法完成一些操作,初始化方法名称和销毁方法名称通过。
- <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="init"
- destroy-method="destroy"/>
-
- public class UserDaoImpl implements UserDao {
- public UserDaoImpl() { System.out.println("UserDaoImpl创建了..."); }
- public void init(){ System.out.println("初始化方法..."); }
- public void destroy(){ System.out.println("销毁方法..."); }
- }
扩展:除此之外,我们还可以通过实现InitializingBean接口,完成一些Bean的初始化操作,如下:
- public class UserDaoImpl implements UserDao, InitializingBean {
- public UserDaoImpl() {System.out.println("UserDaoImpl创建了...");}
- public void init(){System.out.println("初始化方法...");}
- public void destroy(){System.out.println("销毁方法...");}
- //执行时机早于init-method配置的方法
- public void afterPropertiesSet() throws Exception {
- System.out.println("InitializingBean...");
- }
- }
Spring的实例化方式主要如下两种:
构造方式实例化Bean又分为无参构造方法实例化和有参构造方法实例化,Spring中配置的<bean>几乎都是无参构造方式,此处不在赘述。下面讲解有参构造方法实例化Bean:
- //有参构造方法
- public UserDaoImpl(String name){
- }
有参构造在实例化Bean时,需要参数的注入,通过<constructor-arg>标签,嵌入在<bean>标签内部提供构造参数,如下:
- <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
- <constructor-arg name="name" value="haohao"/>
- </bean>
工厂方式实例化Bean,又分为如下三种:
静态工厂方法实例化Bean,其实就是定义一个工厂类,提供一个静态方法用于生产Bean实例,在该工厂类机器静态方法配置给Spring即可
- //工厂类
- public class UserDaoFactoryBean {
- //非静态工厂方法
- public static UserDao getUserDao(String name){
- //可以在此编写一些其他逻辑代码
- return new UserDaoImpl();
- }
- }
PS:<constructor-arg>标签不仅仅是为构造方法传递参数,只要是为了实例化对象而传递的参数都可以通过 <constructor-arg>标签完成,例如上面通过静态工厂方法实例化Bean所传递的参数也是要通过<constructor-arg> 进行传递的
测试代码,直接通过ApplicationContext获得userDao即可
- ApplicationContext applicationContext =
- new ClassPathxmlApplicationContext("applicationContext.xml");
- Object userDao = applicationContext.getBean("userDao");
- System.out.println(userDao);
断点调试,UserDaoImpl实例对象会存在于单例池中
实例工厂方法,也就是非静态工厂方法产生Bean实例,与静态工厂方式比较,该方式需要先有工厂对象,在用工厂 对象去调用非静态方法,所以在进行配置时,要先配置工厂Bean,在配置目标Bean
- //工厂类
- public class UserDaoFactoryBean2 {
- //非静态工厂方法
- public UserDao getUserDao(String name){
- //可以在此编写一些其他逻辑代码
- return new UserDaoImpl();
- }
- }
实例工厂方法,也就是非静态工厂方法产生Bean实例,与静态工厂方式比较,该方式需要先有工厂对象,在用工厂 对象去调用非静态方法,所以在进行配置时,要先配置工厂Bean,在配置目标Bean
测试代码通上,直接通过ApplicationContext获得userDao即可,不在赘述
通过断点观察单例池singletonObjects,发现单例池中既有工厂Bean实例,也有目标Bean实例,且都是在Spring 容器创建时,就完成了Bean的实例化
上面不管是静态工厂方式还是非静态工厂方式,都是自定义的工厂方法,Spring提供了FactoryBean的接口规范, FactoryBean接口定义如下:
- public interface FactoryBean<T> {
- String OBJECT_TYPE_ATTRIBUTE = “factoryBeanObjectType”;
- T getObject() throws Exception; //获得实例对象方法
- Class<?> getObjectType(); //获得实例对象类型方法
- default boolean isSingleton() {
- return true;
- }
- }
定义工厂实现FactoryBean
- public class UserDaoFactoryBean3 implements FactoryBean<UserDao> {
- public UserDao getObject() throws Exception {
- return new UserDaoImpl();
- }
- public Class<?> getObjectType() {
- return UserDao.class;
- }
- }
配置FactoryBean交由Spring管理配置
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean3"/>
通过Spring容器根据beanName可以正常获得UserDaoImpl
- ApplicationContext applicationContext =
- new ClassPathxmlApplicationContext("applicationContext.xml");
- Object userDao = applicationContext.getBean("userDao");
- System.out.println(userDao);
通过断点观察发现Spring容器创建时,FactoryBean被实例化了,并存储到了单例池singletonObjects中,但是 getObject() 方法尚未被执行,UserDaoImpl也没被实例化,当首次用到UserDaoImpl时,才调用getObject() , 此工厂方式产生的Bean实例不会存储到单例池singletonObjects中,会存储到 factoryBeanObjectCache 缓存池 中,并且后期每次使用到userDao都从该缓存池中返回的是同一个userDao实例
Bean的依赖注入有两种方式:
其中,ref 是 reference 的缩写形式,翻译为:涉及,参考的意思,用于引用其他Bean的id。value 用于注入普通 属性值。
依赖注入的数据类型有如下三种:
注入 List<T> 集合 – 普通数据
注入 List<T> 集合 – 引用数据
注入 List<T> 集合 – 引用数据
也可以直接引用容器中存在的Bean
注入 Set<T> 集合
注入 Map<K,V> 集合
注入 Properties 键值对
扩展:自动装配方式
如果被注入的属性类型是Bean引用的话,那么可以在<bean> 标签中使用 autowire 属性去配置自动注入方式,属
性值有两个:
- <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"
- autowire="byType">
(8)SpringBean的配置详解
Spring的xml标签大体上分为两类,一种是默认标签,一种是自定义标签
Spring的默认标签用到的是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"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
- </beans>
该命名空间约束下的默认标签如下
<beans>标签,除了经常用的做为根标签外,还可以嵌套在根标签内,使用profile属性切换开发环境
可以使用以下两种方式指定被激活的环境:
<import>标签,用于导入其他配置文件,项目变大后,就会导致一个配置文件内容过多,可以将一个配置文件根 据业务某块进行拆分,拆分后,最终通过<import>标签导入到一个主配置文件中,项目加载主配置文件就连同 <import> 导入的文件一并加载了
- <!--导入用户模块配置文件-->
- <import resource="classpath:UserModuleApplicationContext.xml"/>
-
- <!--导入商品模块配置文件-->
- <import resource="classpath:ProductModuleApplicationContext.xml"/>
<alias> 标签是为某个Bean添加别名,与在<bean> 标签上使用name属性添加别名的方式一样,我们为 UserServiceImpl指定四个别名:aaa、bbb、xxx、yyy
- <!--配置UserService-->
- <bean id="userService" name="aaa,bbb" class="com.itheima.service.impl.UserServiceImpl">
- <property name="userDao" ref="userDao"/>
- </bean>
- <!--指定别名-->
- <alias name="userService" alias="xxx"/>
- <alias name="userService" alias="yyy"/>
断点调试,在beanFactory中维护着一个名为aliasMap的Map<String,String>集合,存储别名和beanName之间的映射关系
Spring的自定义标签需要引入外部的命名空间,并为外部的命名空间指定前缀,使用 <前缀:标签> 形式的标签,称之为自定义标签,自定义标签的解析流程也是 Spring xml扩展点方式之一,在《Spring整合其他框架》章节进行详细介绍
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。