Spring4学习:在Ioc容器中装配Bean

来源:互联网 发布:合肥市数据资源局王伟 编辑:程序博客网 时间:2024/06/08 01:31

一、基于Schema的配置格式:


命名空间的定义分为两步:第一步指定命名空间的名称;第二步指定命名空间的Schema文档格式文件的位置,用空格或回车换行进行分隔。

在第一步中需要指定命名空间的缩略名和全名,比如:xmlns:aop="http://www.springframework.org/schema/aop",aop为命名空间的别名,一般使用简介易记的名称,文档后面的元素可通过命名空间别名加以区分,如<aop:config/>等。如果命名空间的别名为空,则表示该命名空间为文档默认命名空间。文档中无命名空间前缀的元素都属于默认命名空间,如<beans/>、<bean/>等都属于在(1)处定义的默认命名空间。

在第二步中,为每个命名空间指定了对应的Schema文档格式的定义文件,定义的语法如下:

<命名空间1> <命名空间1Schema文件> <命名空间2> <命名空间2Schema文件>

二、Bean基本配置

在配置一个Bean时,需要为其指定一个id属性为Bean的名称。id在IoC容器中必须是唯一的,id的命名必须以字母开始,后面可以是字母、数字、连字符、下划线、句号、冒号等完成结束的符号,逗号和空格这些非完整结束符是非法的。也可以为bean指定name属性,name属性几乎可以使用任何字符。

当出现多个name相同的<bean>时,通过getBean(beanName)获取Bean时,将返回后面声明的那个Bean。

如果id和name属性都未指定,那么Spring自动将全限定类名作为Bean的名称。如果存在多个实现类相同的匿名<bean>,如下:

<bean class="com.smart.simple.Car"/>

<bean class="com.smart.simple.Car"/>

<bean class="com.smart.simple.Car"/>

第一个Bean通过getBean("com.smart.simple.Car")获得;第二个Bean通过getBean("com.smart.simple.Car#1")获得;第三个通过getBean("com.smart.simple.Car#2")获得,以此类推。

三、依赖注入

1、属性注入

属性注入要求Bean提供一个默认的构造函数,并为需要注入的属性提供对应的setter方法。Spring先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用setter方法注入属性值。如下代码所示:

<bean id="boss2" class="com.smart.ditype.Boss"><property name="name" value="John" /><property name="car" ref="car" /></bean>
注:(1)、如果类中没有定义任何构造函数,则JVM会自动为其生成一个默认的构造函数,如果类中显式定义了一个带参构造函数,则JVM不会为其生成默认的构造函数,则需要提供一个带参构造函数和一个默认的构造函数。

(2)、配置文件中<property name="name"/>的属性配置项仅要求Boss类中拥有setName()方法,但Boss类不一定拥有name成员变量。

(3)JavaBean关于属性命名的特殊规范:JavaBean允许以大写字母开头的属性变量名,不过必须满足"变量的前两个字母要么全部大写,要么全部小写"的要求。

2、构造函数注入

使用构造函数注入的前提是Bean必须提供带参的构造函数。

(1)按类型匹配入参

<bean id="car1" class="com.smart.ditype.Car"><constructor-arg type="java.lang.String"><value>红旗CA72</value></constructor-arg><constructor-arg type="double"><value>20000</value></constructor-arg></bean>
<constructor-arg>的元素中有一个type属性,它为Spring提供了判断配置项和构造函数入参对应关系的依据。注意<constructor-arg>的位置并不会对最终的配置效果产生影响。

(2)按索引匹配入参

<bean id="car4" class="com.smart.ditype.Car"><constructor-arg index="0"><value>红旗CA72</value></constructor-arg><constructor-arg index="1"><value>中国一汽</value></constructor-arg></bean>
(3)联合使用类型和索引匹配入参

<bean id="car3" class="com.smart.ditype.Car"><constructor-arg index="0" type="java.lang.String"><value>红旗CA72</value></constructor-arg><constructor-arg index="1" type="java.lang.String"><value>中国一汽</value></constructor-arg><constructor-arg index="2" type="int"><value>200</value></constructor-arg></bean>
(4)通过自身类型反射匹配入参

当Bean构造函数入参的类型是可辨的(非基础数据类型且入参类型各异),由于Java反射机制可以获取构造函数入参的类型,构造函数注入的配置可以不提供类型和索引信息。如下所示:

<bean id="boss1" class="com.smart.ditype.Boss"><constructor-arg><value>John</value></constructor-arg><constructor-arg><ref bean="car" /></constructor-arg><constructor-arg><ref bean="office" /></constructor-arg></bean>

注意:当两个Bean都采用构造函数注入,而且都通过构造函数入参引用对方,就会发生类似线程死锁的循环依赖问题,这种情况下要将构造函数注入方式调整为属性注入方式。

3、工厂方法注入

(1)非静态工厂方法

必须实例化工厂类后才能调用工厂方法

<bean id="carFactory" class="com.smart.ditype.CarFactory" /><bean id="car5" factory-bean="carFactory" factory-method="createHongQiCar"></bean>

(2)静态工厂方法

用户在无须创建工厂类实例的情况下就可以调用工厂类方法

四、注入参数详解

1、字面值

XML中有5个特殊字符,分别是&、<、>、"、'。如果配置文件中的注入值包括这些特殊字符,就需要进行特别处理。两种方法解决:1是采用<![CDATA[ ]]>特殊标签,将包含特殊字符的字符串封装起来;2是使用XML转义序列表示这些特殊字符,这5个特殊字符对应的XML转义序列如下所示:


2、引用其他Bean

<ref>元素可以通过以下3个属性引用容器中的其他Bean

(1)bean:通过该属性可以引用统一容器或父容器中的Bean

(2)local:通过该属性只能引用同一配置文件中定义的Bean

(3)parent:引用父容器中的Bean,如<ref parent="car">

3、内部Bean

如果car Bean只被boss Bean引用,而不被容器中任何其他的Bean引用,则可以将car以内部Bean的方式注入Boss中。如下所示:

<bean id="boss2" class="com.smart.attr.Boss"><property name="car"><bean class="com.smart.attr.Car"><property name="maxSpeed" value="200" /><property name="price" value="2000.00" /></bean></property></bean>

4、null值

Spring会将<value></value>解析为空字符串。如果为属性设置为一个null的注入值,必须使用专用的<null/>元素标签,通过它可以为Bean的字符串或其他对象类型的属性注入null值。

5、级联属性

如果我们希望在定义Boss式直接为其属性Car的属性提供注入值,则可以采用以下配置:

<bean id="boss" class="com.smart.attr.Boss"><property name="car.brand" value="吉利CT50"/></bean>

6、集合类型属性

(1)List和Set

如下为Boss添加一个List类型的favorites属性

<bean id="parentBoss" abstract="true" class="com.smart.attr.Boss"><property name="favorites"><list>//改成<set><value>看报</value><value>赛车</value><value>高尔夫</value></list>//改成</set></property></bean>
List属性既可以通过<value>注入字符串,也可以通过<ref>注入容器中其他的Bean。

(2)Map

<bean id="boss1" class="com.smart.attr.Boss"><property name="jobs"><map><entry ><key><value>AM</value></key><value>会见客户</value></entry><entry><key><value>PM</value></key><value>公司内部会议</value></entry></map></property></bean>
如果某一Map元素的键和值都是对象,可以用如下方式配置:

<entry ><key><ref bean="keyBean"/></key><ref bean="valueBean"/></entry>
(3)Properties

Properties类型其实可看作Map类型的特例。Map元素的键和值可以是任何类型的对象,而Properties属性的键和值都只能是字符串。

<property name="mails"><props><prop key="jobMail">john-office@smart.com</prop><prop key="lifeMail">john-life@smart.com</prop></props></property>
(4)集合合并

Spring允许子<bean>继承父<bean>的同名属性集合元素,并将子<bean>中配置的集合属性值和父<bean>中配置的同名属性值合并起来作为最终Bean的属性值,如下所示:

<bean id="parentBoss" abstract="true"class="com.smart.attr.Boss"><property name="favorites"><set><value>看报</value><value>赛车</value><value>高尔夫</value></set></property></bean><bean id="childBoss" parent="parentBoss"><property name="favorites"><set merge="true"><value>爬山</value><value>游泳</value></set></property></bean>

7、简化配置方式


使用p命名空间


对于字面值属性,其格式为:p:<属性名>=“xxx”

对于引用对象的属性,其格式为:p<属性名>-ref="xxx"

8、自动装配

<bean>元素提供了一个指定自动装配类型的属性:autowire=“<自动装配类型>”。Spring提供了4中自动装配类型,如下:


<beans>元素标签中的default-autowire属性可以配置全局自动匹配,default-autowire属性默认值为no,表示不启用自动装配。在<beans>中定义的自动装配策略可以被<bean>的自动装配策略覆盖。在实际开发中,XML配置方式很少启用自动装配,而基于注解的配置方式默认采用byType自动装配策略。

五、方法注入

1、lookup方法注入

lookup方法注入是有一定使用范围的,一般希望通过一个singleton Bean获取一个prototype Bean时使用。

<bean id="magicBoss" class="com.smart.injectfun.MagicBoss" >    <lookup-method name="getCar" bean="car"/></bean>
通过lookup-method元素标签为MagicBoss的getCar()提供动态实现,返回prototype类型的car Bean,这样Spring将在运行期为MagicBoss接口提供动态实现。

2、方法替换

用于替换他人的Bean必须实现MethodReplacer接口,Spring将利用该接口的方法去替换目标Bean的方法。

<bean id="boss2" class="com.smart.injectfun.Boss2"/><bean id="boss1" class="com.smart.injectfun.Boss1">     <replaced-method name="getCar" replacer="boss2"></replaced-method></bean>
上面的代码使用Boss2的方法去替换Boss1的getCar()方法。

六、Bean之间的关系

1、继承

<bean id="abstractCar" class="com.smart.tagdepend.Car"  p:brand="红旗CA72" p:price="2000.00" p:color="黑色"  abstract="true"/>  <bean id="car3" parent="abstractCar"><property name="color" value="红色"/></bean><bean id="car4" parent="abstractCar" ><property name="color" value="白色"/></bean>
可以把子bean相同的属性抽取出来放在父bean中,一般在父bean中要声明abstract=“true”

2、依赖

Spring运行用户通过depends-on属性显式指定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好。如果前置依赖多个Bean,则可以通过逗号、空格或分号的方式创建Bean的名称。

<bean id="cacheManager" class="com.smart.tagdepend.CacheManager" depends-on="sysInit" /><bean id="sysInit" class="com.smart.tagdepend.SysInit" />

3、引用

可以通过<idref>引用另一个<bean>的名字。

<bean id="car" class="com.smart.tagdepend.Car"/>    <bean id="boss" class="com.smart.tagdepend.Boss" >       <property name="carId"  >           <idref bean="car"/>       </property>    </bean>

七、整合多个配置文件

Spring允许通过<import>将多个配置文件引入到一个文件中,进行配置文件的集成。这样,在启动Spring容器时,仅需指定这个合并好的配置文件即可。

八、Bean作用域


1、singleton作用域

Spring的ApplicationContext容器在启动时,自动实例化所有singleton的Bean并缓存于容器中。虽然启动时会花费一些时间,但有两个好处:一是对Bean提前进行实例化操作会及早发现一些潜在的配置问题;二是Bean以缓存的方式保存,当运行时用到该Bean时无须再实例化,提高了运行效率。如果用户不希望在容器启动时提前实例化singleton的Bean,则可以通过lazy-init属性进行控制。

<bean id="boss1" class="com.smart.scope.Boss" p:car-ref="car" lazy-init="true"/>

2、prototype作用域

默认情况下,Spring容器在启动时不实例化prototype的Bean。

3、与Web应用环境相关的Bean的作用域

如果用户使用Spring的WebApplicationContext,则可使用另外3种Bean作用域:request、session、globalSession。在使用这些作用域之前,必须在Web容器中进行一些额外的配置。

在低版本的Web容器中,用户可以使用HTTP请求过滤器进行配置。

<web-app><filter><filter-name>requestContextFilter</filter-name><filter-class>org.springframework.web.filter.RequestContextFilter</filter-class></filter><filter-mapping><filter-name>requestContextFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>
在高版本的Web容器中,则可以利用HTTP请求监听器进行配置

<web-app>    <listener>        <listener-class>            org.springframework.web.context.request.RequestContextListener        </listener-class>    </listener></web-app>
在整合Spring容器时使用ContextLoaderListener,它实现了ServletContextListener监听器接口,ServletContextListener只负责监听Web容器启动和关闭的事件。而RequestContextListener实现了ServletRequestListener监听器接口,该监听器监听HTTP请求事件,Web服务器接收的每一次请求都会通知该监听器。

(1)、request作用域

<bean name="car"  class="com.smart.scope.Car"  scope="request"/>

每次HTTP请求调用car Bean时,Spring容器就会创建一个新的car Bean;请求处理完毕后,就会销毁这个Bean。

(2)、session作用域

<bean name="car"  class="com.smart.scope.Car"  scope="session"/>
car Bean的作用域横跨整个HTTP  Session,Session中的所有HTTP请求都共享同一个car Bean。当HTTP Session结束后,实例才被销毁。

(3)、globalSession作用域

globalSession作用域类似于session作用域,不过仅在Portlet的Web应用中使用。

(4)、作用域依赖问题

当非Web相关作用域的Bean引用Web作用域的Bean时,需要使用aop代理。如下:


当boss Bean在Web环境下调用car Bean时,Spring AOP将启用动态代理智能地判断boss Bean位于哪个HTTP请求线程中,并从对应的HTTP请求线程域获得对应的car Bean。

九、基于注解的配置

1、使用注解定义Bean

(1)@Component注解在某个类上,Spring容器自动将POJO类转换为容器管理的Bean

(2)@Repository:用于对DAO实现类进行标注

(3)@Service:用于对Service实现类进行标注

(4)@Controller:用于对Controller实现类进行标注

之所以要在@Component之外提供这3个特殊的注解,是为了让标注类本身的用途清晰化,完全可以用@Component替代这3个特殊的注解。

2、扫描注解定义的Bean

Spring提供了context命名空间,它提供了通过扫描类包以应用注解定义Bean的方式,如下:

<?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-4.0.xsd         http://www.springframework.org/schema/context         http://www.springframework.org/schema/context/spring-context-4.0.xsd">   <context:component-scan base-package="com.smart.anno"/></beans>
通过context命名空间的component-scan的base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里的所有类,并从类的注解信息中获取Bean的定义信息。

如果仅希望扫描特定的类而非基包下的所有类,那么可以使用resource-pattern属性过滤出特定的类,如下:

<context:component-scan base-package="com.smart" resource-pattern="anno/*.class"/>

这里将基类包设置为com.smart;默认情况下resource-pattern属性的值为“**/*.class”,即基类包里的所有类,将其设置为“anno/*.class”,则Spring仅会扫描基类包里anno子类包的类。

如果仅需要过滤基类包中实现了XxxService接口的类或标注了某个特定注解的类等,则要用<context:component-scan>的过滤子元素实现,如下:

<context:component-scan base-package="com.smart">   <context:include-filter type="regex" expression="com\.smart\.anno.*Dao"/>   <context:include-filter type="regex" expression="com\.smart\.anno.*Service"/>   <context:exclude-filter type="aspectj" expression="com.smart..*Controller+"/></context:component-scan >
<context:include-filter>表示要包含的目标类,而<context:exclude-filter>表示要排除的目标类。这两个过滤元素支持多种类型的过滤表达式,如下:


<context:component-scan/>的use-default-filters属性,其默认值为true,表示默认会对标注@Component、@Controller、@Service及@Reposity的Bean进行扫描。

3、自动装配Bean

(1)、使用@Autowired进行自动注入

@Autowired默认按类型(byType)匹配的方式在容器中查找匹配的Bean,当且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。

如果容器中没有一个和标注变量类型匹配的Bean,那么Spring容器启动时将报NoSuchBeanDefinitionException异常。如果希望Spring即使找不到匹配的Bean完成注入也不要抛出异常,那么可以使用@Autowired(required=false)进行标注

(2)、使用@Qualifier指定注入Bean的名称

如果容器中有一个以上匹配的Bean时,则可以通过@Qualifier注解限定Bean的名称,如下:

@Autowired@Qualifier("userDao")private UserDao userDao;
(3)、对类方法进行标注

@Autowired可以对类成员变量及方法的入参进行标注,如果一个方法拥有多个入参,则在默认情况下,Spring将自动选择匹配入参类型的Bean进行注入。Spring允许对方法入参标注@Qualifier以指定注入Bean的名称。如下:

@Autowiredpublic void init(@Qualifier("userDao")UserDao userDao,LogDao logDao){System.out.println("multi param inject");this.userDao = userDao;this.logDao =logDao;}
(4)、对集合类进行标注

如果对类中集合类的变量或方法入参进行@Autowired标注,那么Spring会将容器中类型匹配的所有Bean都自动注入进来。

@Componentpublic class MyComponent {@Autowired(required=false)private List<Plugin> plugins;@Autowired //(1)private Map<String,Plugin> pluginMaps;public List<Plugin> getPlugins() {return plugins;}}
在(1)处将实现Plugin接口的Bean注入Map集合,是Spring4.0提供的新特性,其中key是Bean的名字,value是所有实现了Plugin的Bean。

在Spring4.0中可以通过@Order注解或实现Ordered接口来决定Bean加载的顺序,值越小,优先被加载。

(5)、对延迟依赖注入的支持

Spring4.0支持延迟依赖注入,即在Spring容器启动时,对于在Bean上标注@Lazy及@Autowired注解的属性,不会立即注入属性值,而是延迟到调用此属性的时候才会注入属性值。对Bean实施延迟依赖注入,要注意@Lazy注解必须同时标注在属性及目标Bean上。

(6)、对标准注解的支持

@Resource注解要求提供一个Bean名称的属性,如果属性为空,则自动采用标注处的变量名或方法名作为Bean的名称。

@Inject和@Autowired同样也是按类型匹配注入Bean的,只不过它没有required属性。

4、Bean作用范围及生命过程方法

通过注解配置的Bean和通过<bean>配置的Bean一样,默认的作用范围都是singleton。Spring为注解配置提供了一个@Scope注解,可以通过他显式指定Bean的作用范围。

Spring从2.5开始支持@PostConstruct和@PreDestroy注解,不过在使用注解时,可以在一个Bean中定义多个@PostConstruct和@PreDestroy方法

十、基于Java类的配置













0 0
原创粉丝点击