Spring4-快速入门之在IOC容器中装配Bean
来源:互联网 发布:java 创建数组 编辑:程序博客网 时间:2024/05/20 11:48
概述
Bean配置信息:
即Bean的元数据信息,包括Bean的实现类,属性信息,依赖关系和行为配置(生命周期及生命周期过程中的回调函数)
Spring容器内部协作接口
首先,容器会根据Bean的配置信息,在容器内部建立Bean定义注册表(一个个BeanDefinition对象),然后根据注册表实例化Bean,并建立Bean和Bean之间的依赖关系,最后将这些准备就绪的Bean放入缓存池中,供外部的应用程序使用
Bean基本配置
基于XML文件的配置方式如下
<bean id="foo1" class="com.spring4.chpter5.Foo"></bean>
除了使用id为Bean命名,还可以使用name为Bean命名,name属性支持多个命名,可以使用空格,分号,或逗号分开
<bean name="foo1 foo2 foo3" class="com.spring4.chpter5.Foo"></bean>
依赖注入
Spring支持3种方式的注入,分别是属性注入,构造函数注入和工厂方法注入
属性注入
通过属性的setter()方法进行注入,要求Bean必须提供一个默认的构造函数,并为需要注入的属性提供setter()方法
public class Car { private String brand; private String color; private String maxSpeed; public void setBrand(String brand) { this.brand = brand; } public void setColor(String color) { this.color = color; } public void setMaxSpeed(String maxSpeed) { this.maxSpeed = maxSpeed; } public void introduce() { System.out.println("brand:" + this.brand + ";color:" + this.color + ";maxSpeed:" + this.maxSpeed); }}<bean id="car" class="com.spring4.chpter5.Car"> <property name="brand" value="影刺HT+"></property> <property name="color" value="黑色"></property> <property name="maxSpeed" value="300"></property> </bean>
注意,Spring只会检查Bean中是否有对应的setter方法,并不关心是否有该属性,例如上面Car类中有setBrand()方法,但却不一定要有brand属性
构造函数注入
使用构造函数注入,要求Bean必须提供带参数的构造函数。例如上面的Car类,提供一个带参数的构造函数。
public Car(String brand,String color,String maxSpeed) { this.brand = brand; this.color = color; this.maxSpeed = maxSpeed; }
bean.xml配置如下:
<!-- 根据构造函数注入 --> <constructor-arg name="color" value="红色"></constructor-arg> <constructor-arg name="brand" value="游侠9"></constructor-arg> <constructor-arg name="maxSpeed" value="350"></constructor-arg>
构造函数注入还提供按索引和按参数类型匹配入参的功能,可以使用constructor-arg标签下的type属性和index属性配置。
注意:循环依赖问题
考虑下面的例子:
Car类的构造函数
public Car(String brand,String color,String maxSpeed,Boss boss) { this.brand = brand; this.color = color; this.maxSpeed = maxSpeed; this.boss = boss; }
Boss类的构造函数
public Boss(String name,Car car) { this.name = name; this.car = car; }
bean.xml配置:
<bean id="car" class="com.spring4.chpter5.Car"> <constructor-arg name="color" value="红色"></constructor-arg> <constructor-arg name="brand" value="游侠9"></constructor-arg> <constructor-arg name="maxSpeed" value="350"></constructor-arg> <constructor-arg name="boss" ref="boss"></constructor-arg </bean> <bean id="boss" class="com.spring4.chpter5.Boss"> <constructor-arg name="name" value="SSS"></constructor-arg> <constructor-arg name="car" ref="car"></constructor-arg> </bean>
由于在使用构造函数注入时,Bean的入参引用的对象必须已经准备就绪,而这里的Car类和Boss类都使用了构造函数注入,而且都互相引用了对方,因此会发生循环依赖问题,两者都会等待对方实例化,就会出现类似线程死锁的问题,SpringIoC容器将不能启动成功。
工厂方法注入
非静态工厂方法:
public Car getCar() { Car car = new Car(); return car; }
<bean id="carFactory" class="com.spring4.chpter5.CarFactory"></bean> <bean id="car2" factory-bean="carFactory" factory-method="getCar"></bean>
静态工厂方法:
public static Car getCar2() { Car car = new Car(); return car; }
<bean id="car3" class="com.spring4.chpter5.CarFactory" factory-method="getCar2"></bean>
注入方式的考量
选择构造函数注入的理由:
1.构造函数注入可以保证一些重要的属性在Bean实例化好之前就设置好,避免因为一些重要属性没有提供而导致一个无用Bean实例的情况
2.不需要为每个属性都设置setter方法,减少方法的数量
3.可以更好的封装类变量,避免外部错误的调用
不选择构造函数注入的理由:
1.如果类的属性过多,bean标签下的constructor-arg标签也会增多,可读性差
2.灵活性不强,如果在有些属性是可选的情况下,通过构造函数注入需要传入null作为默认值
3.不利于类的继承和扩展,因为子类也需要引用父类的构造函数
4.会造成循环依赖问题
部分注入参数介绍
1.当注入的属性包含了XML的特殊字符时,可以使用
<property name="brand"><value><![CDATA[影刺HT+&游侠999]]></value></property>
2.引用其他Bean
通过ref标签引用其他的Bean,ref标签包含两个属性,bean和parent,bean属性表示引用当前容器中的Bean,如果没有,则引用父容器中的Bean;parent属性表示引用父容器中的Bean。
父容器bean.xml:
<bean id="car" class="com.spring4.chpter5.Car"> <property name="brand"><value><![CDATA[影刺HT+&游侠999]]></value></property> <property name="color" value="黑色"></property> <property name="maxSpeed" value="300"></property> </bean>
子容器bean2.xml:
<bean id="car" class="com.spring4.chpter5.Car"> <property name="brand"><value>New棉花糖Black></value></property> <property name="color" value="黑色"></property> <property name="maxSpeed" value="300"></property> </bean> <bean id="boss" class="com.spring4.chpter5.Boss"> <constructor-arg name="name" value="SSS"></constructor-arg> <constructor-arg name="car"> <!-- <ref bean="car"/> --> <!-- 打印结果为brand:New棉花糖Black>;color:黑色;maxSpeed:300 --> <ref parent="car"/> <!-- 打印结果为brand:影刺HT+&游侠999;color:黑色;maxSpeed:300 --> </constructor-arg> </bean>
3.内部Bean
内部Bean和Java的匿名内部类相似,没有名字,也不能被其他Bean引用,只能在声明处为外部Bean提供实例注入
<bean id="boss" class="com.spring4.chpter5.Boss"> <bean class="com.spring4.chpter5.Car"> <property name="brand"><value>New棉花糖></value></property> <property name="color" value="绿色"></property> <property name="maxSpeed" value="280"></property> </bean> </constructor-arg> </bean>
4.null值
通过标签为属性注入null值
<bean id="boss" class="com.spring4.chpter5.Boss"> <bean class="com.spring4.chpter5.Car"> <property name="brand"><value>New棉花糖></value></property> <property name="color" value="绿色"></property> <property name="maxSpeed"><null></null></property> </bean> </constructor-arg> </bean>
5.级联属性
以圆点(.)的方式定义级联属性
<property name="car.brand" value="黑色甲虫9"></property>
6.定义集合属性
例如:为Boss类添加一个List类型的favorites属性
public class Boss { private List<String> favorites = new ArrayList<String>(); ...}
Spring配置如下:
<property name="favorites"> <list> <value>吃饭</value> <value>睡觉</value> <value>打豆豆</value> </list></property>
注意:不仅仅是List类型的属性,数组类型(int[],String[])的属性也可以通过这种方式进行注入
Map类型和Set类型的注入方式与List类似
<!-- 注入Set类型的数据 --> <property name="favorites"> <set> <value>吃饭</value> <value>睡觉</value> <value>打豆豆</value> </set> </property> <!-- 注入Map类型的数据 --> <property name="jobs"> <map> <!-- 一个entry代表一个键值对 --> <entry key="AM" value="MA"></entry> <entry key="WW" value="CC"></entry> </map> </property>
除此之外,List,Set,Map也可以使用Bean作为注入的对象,可通过注入
<list> <ref bean="beanName" /></list><set> <ref bean="beanName"/></set><map> <entry key-ref="beanName" value-ref="beanName"></entry></map>
Properties类型的属性注入
Properties与Map的区别在于,Properties只支持key和value为字符串。
<property name="props"> <props> <prop key="key1">value1</prop> <prop key="key2">value2</prop> </props></property>
通过util命名空间配置集合类型的Bean
如果希望配置一个集合类型的Bean,而不是一个集合类型的属性,可以使用util命名空间进行配置,需要在Spring配置文件中引入util命名空间的声明。
xmlns:util="http://www.springframework.org/schema/util"http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-4.0.xsd
配置一个List类型的Bean,可以通过list-class属性显示的指定List的实现类
<util:list id="list1" list-class="java.util.LinkedList"> <value>吃饭</value> <value>睡觉</value> <value>打豆豆</value></util:list>
配置一个Set类型的Bean,可以通过set-class属性显示的指定Set的实现类
<util:set id="set1" set-class="java.util.HashSet"> <value>吃饭</value> <value>睡觉</value> <value>打豆豆</value></util:set>
配置一个Map类型的Bean,可以通过map-class属性显示的指定Map的实现类
<util:map id="map1" map-class="java.util.HashMap"> <entry key="AM" value="MA"></entry> <entry key="WW" value="CC"></entry></util:map>
方法注入
1.lookup方法注入
声明一个MagicBoss接口,并声明一个getCar()方法,现在通过lookup方法注入,使每次调用getCar()方法都返回一个新的car Bean
public interface MagicBoss { public Car getCar();}
<bean id="car" class="com.spring4.chpter5.Car" scope="prototype"><!-- 这里要设置car为prototype --> <property name="brand"><value>New棉花糖Black></value></property> <property name="color" value="黑色"></property> <property name="maxSpeed" value="300"></property></bean><bean id="magicBoss" class="com.mjf.spring4.chpter5.MagicBoss"> <lookup-method name="getCar" bean="car"/></bean>
2.方法替换
Bean实现MethodReplacer接口后,可以使用该接口的方法去替换目标Bean的方法
例如:
Boss1的getCar()方法返回Car1
public class Boss1 { public Car getCar() { Car car = new Car(); car.setBrand("Car1"); return car; }}
Boss2实现了org.springframework.beans.factory.support.MethodReplacer接口,该接口返回Car2
public class Boss2 implements MethodReplacer{ @Override public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { Car car = new Car(); car.setBrand("Car2"); return car; }}
Spring配置如下
<bean id="boss1" class="com.mjf.spring4.chpter5.Boss1"> <!-- 使用boss2的reimplement方法替换boss1的getCar方法 --> <replaced-method name="getCar" replacer="boss2"></replaced-method></bean><bean id="boss2" class="com.mjf.spring4.chpter5.Boss2"></bean>
Bean之间的继承和依赖
1.继承
通过继承,子bean会继承父bean的所有配置信息
<bean id="car" class="com.spring4.chpter5.Car" scope="prototype"> <property name="brand"><value>New棉花糖Black></value></property> <property name="color" value="黑色"></property> <property name="maxSpeed" value="300"></property> </bean> <!-- 继承car Bean,brand和maxSpeed属性与car一致 --> <bean id="car2" class="com.spring4.chpter5.Car" scope="prototype" parent="car"> <property name="color" value="红色"></property> </bean>
2.依赖
通过depends-on属性,显式的指定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好
<!-- boss3会在mycar实例化完成后,在实例化 --> <bean id="boss3" class="com.spring4.chpter5.Boss" depends-on="mycar"></bean> <bean id="mycar" class="com.spring4.chpter5.Car"></bean>
整合多个配置文件
通过import标签将多个xml配置文件整合到一起
<import resource="classpath*:com/spring4/chpter5/bean.xml"/>
Bean的作用域
注意:当非web相关作用域的Bean引用web相关作用域的Bean时,需要与Spring的动态代理技术一起使用,如下:
<!-- 根据代理,判断boss5需要取得那个HTTP请求相关的car Bean --> <bean id="car5" class="com.spring4.chpter5.Car" scope="request"> <aop:scoped-proxy/><!-- 创建代理 --> </bean> <bean id="boss5" class="com.spring4.chpter5.Boss" scope="singleton"> <property name="car" ref="car5"></property><!-- 引用web相关作用域的Bean --> </bean>
基于注解的配置
1.使用注解定义的Bean
将class定义为Bean的注解类别:
2.扫描注解定义的Bean
Spring提供了一个Context的命名空间,它提供了通过扫描类包以应用注解定义Bean的方式,如下:
<!-- 声明Context的命名空间 -->xmlns:context="http://www.springframework.org/schema/context"http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"><!-- 扫描类包以应用注解定义的Bean --><context:component-scan base-package="com.spring4.chpter5"></context:component-scan>
3.自动装配Bean
使用@Autowired进行自动注入(默认使用byType的方式)
@Autowiredprivate Car car;
将@Autowired的required属性设置为false,即使Spring找不到匹配的Bean,也不会抛出异常
可以使用@Qualifier注解指定注入的Bean的名称
@Autowired@Qualifier("car")//注入名为car的Beanprivate Car car;
@Autowired和@Qualifier除了能注解属性外,还可以注解方法,如下:
@Autowiredpublic Boss(String name,@Qualifier("car") Car car) { System.out.println("Boss Constructor"); this.name = name; this.car = car;}
使用@Lazy注解指定延迟依赖注入,注意@Lazy注解必须同时标注在属性和目标Bean上,否则无效。
4.Bean作用范围和生命过程方法
使用@Scope注解指定Bean的作用范围,例如:@Scope(“prototype”)。
使用@PostConstruct和@PreDestory注解指定Bean的初始化及容器销毁前执行的方法,可以标注多个方法。
基于Java类的配置
1.使用Java类提供Bean定义信息
使用@Configuration将一个POJO标注定义为Bean的配置类(我的理解是,同xml配置文件类似,也可以作为bean标签使用)
使用@Bean注解标注方法,提供Bean的定义信息(和bean标签类似)
例如:
@Configurationpublic class AppConf { @Bean public Boss1 getBoss1() { Boss1 boss1 = new Boss1(); return boss1; } @Bean public Car getCar() { Car car = new Car(); return car; }}
上面的代码等同于
<bean id="AppConf" class="com.spring4.chpter5.AppConf"></bean> <bean id="getBoss1" class="com.spring4.chpter5.Boss1"></bean> <bean id="getCar" class="com.spring4.chpter5.Car"></bean>
- Spring4-快速入门之在IOC容器中装配Bean
- Spring4学习:在Ioc容器中装配Bean
- 在IoC容器中装配Bean
- 3.在IOC容器中装配Bean
- 在IoC容器中装配Bean
- 在IoC容器中装配Bean
- IoC容器中装配Bean
- Spring4.3入门 Ioc 容器中配置bean
- 第二篇 小曹学spring--在IoC容器中装配Bean
- spring3.x第四章 在IOC容器中装配Bean
- spring学习(四):在IOC容器中装配Bean
- 浅谈spring IOC容器中装配bean
- 5.Spring4.x学习[核心篇][Spring在IOC中装配Bean](1)
- 5.Spring4.x学习[核心篇][Spring在IOC中装配Bean](2)
- Spring4快速入门第四章注解装配bean属性
- Ioc容器装配Bean(2)
- IoC容器装配Bean 上
- IoC容器装配Bean 下
- 融云集成-IM即时通讯
- SlidingPaneLayout点击事件穿透
- [空白] 大丈夫!
- c语言入门:指针的使用
- 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
- Spring4-快速入门之在IOC容器中装配Bean
- Python编程入门学习笔记——搭建编程环境
- Win8.1以及win10以上系统 安装msi文件方法
- SLAM/openCV基础笔记
- Lintcode157 Unique Characters solution 题解
- Javaweb-xml编程-考生成绩管理系统(1)
- 学习samtools
- 反射reflect
- JavaWeb学习笔记-java基础-9-javabean(2)