配置形式:
- 基于XML文件的方式
- 基于注解的方式
(为了使文章不至于过于亢长,一些配置知识和技巧会在2.x的文章中进行阐述)
1 .基于XML文件的方式
- bean类的一个测试示例
public class HelloWorld {
private String name;
public void setName(String name) {
this.name = name;
System.out.println("helloworld set name = "+name);
}
public void hello() {
System.out.println("hello "+name);
}
public HelloWorld() {
super();
System.out.println("helloWorld's constructor is running");
// TODO Auto-generated constructor stub
}
}
- xml文件中对bean的配置
<!-- 配置bean -->
<bean id="helloWorld" class="thread.conor.spring.beans.HelloWorld">
<property name="name" value="Spring"></property>
</bean>
其中id为这个bean的id(后面Main类中要用到),这个class中的是你写的HelloWord的全类名,其中property中配置这个bean的属性,name中的是原来那个类中属性的属性名,value中的是赋给这个属性的属性值
- 使用bean类(将后三行注释去掉即为使用该bean类对象的具体方式,在这里我想对创建Spring的IOC容器时具体对HelloWorld类做了什么做一个测试)
public class Main {
public static void main(String[] args) {
//此处的applicationContext.xml即为配置bean时所使用的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//这里的“helloWorld”字符串与applicationContext.xml文件中的标签中的id属性相对应
// HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
// System.out.println(helloWorld);
// helloWorld.hello();
}
}
直接运行的结果
原理分析
这里介绍一下此程序的思路。
- 目的:创建并测试这个HelloWorld类的实例对象
- 步骤
- 编写HelloWorld类
- 在项目根目录下(就是你项目下的第一级目录)创建并编写xml文件来配置Bean对象。
- 编写Main类测试这个Bean对象(其中你需要创建一个IOC容器实现ApplicationContext接口的实体类,而你所配置好的Bean对象就在这个IOC容器中,可以通过它的方法来得到)
- 思考:为什么不适用new关键词直接创建这个HelloWorld的对象,而是使用这么大费周章的方式来创建这个HelloWorld的对象?
这也是IOC/DI(资源反转/依赖注入)的含义所在。如果使用new关键词那么我们对HelloWorld这个类的属性配置就只能在程序体中实现,那么当我在程序为这个name属性赋什么值的时候,它就只能显示出什么值,这样设置name属性的“权力”就只有程序编写者一人拥有。但是如果使用这种方式来配置,那么设置name属性的值的“权力”就由所有能访问并可以修改这个配置文件的人所拥有,而从程序编写者的角度来思考,这里的name属性好像就不是他自己所编写的,而是从外界“注入进来”的,这就是DI依赖注入的含义。
以此类推,Spring的IOC部分就是这样,这里是将“权力”交给配置文件的访问者,而其他方面,比如说在网络服务器的应用方面,无非是将权力交给”客户“,由客户的行为来为对象的属性赋值,来对对象进行改动,只不过客户是不知道的,这边对于客户是一个黑箱,他不知道他在网页或者是软件中的操作会对我们的后台服务器造成什么影响,但是从程序员的角度来看,这些操作都是在对对象的状态进行某种改变。
这里,我将后三行对HelloWorld对象的获取和使用的代码进行注释,便于来测试HelloWorld对象是什么时候被创建,如何被创建的。
测试结果说明,在我创建这个Spring 的IOC 容器的对象时,该Bean对象就已被加载和创建了,而且里面的属性值都创建好了,又一次说明DI依赖注入的比喻是恰当的。
xml配置Bean属性的细节:
此处引用尚硅谷的课件
- 通过setter为bean配置属性
<!-- 配置一个 bean -->
<bean id="helloWorld" class="com.atguigu.spring.helloworld.HelloWorld">
<!-- 为属性赋值 -->
<property name="user" value="Jerry"></property>
</bean>
- 通过构造器为bean配置属性
<!-- 若一个 bean 有多个构造器, 如何通过构造器来为 bean 的属性赋值 -->
<!-- 可以根据 index 和 value 进行更加精确的定位. (了解) -->
<bean id="car" class="com.atguigu.spring.helloworld.Car">
<constructor-arg value="KUGA" index="1"></constructor-arg>
<constructor-arg value="ChangAnFord" index="0"></constructor-arg>
<constructor-arg value="250000" type="float"></constructor-arg>
</bean>
<bean id="car2" class="com.atguigu.spring.helloworld.Car">
<constructor-arg value="ChangAnMazda"></constructor-arg>
<!-- 若字面值中包含特殊字符, 则可以使用 DCDATA 来进行赋值. (了解) -->
<constructor-arg>
<value><![CDATA[<ATARZA>]]></value>
</constructor-arg>
<constructor-arg value="180" type="int"></constructor-arg>
</bean>
- 通过对配置文件中另一个bean的引用来配置当前bean
<bean id="dao5" class="com.atguigu.spring.ref.Dao"></bean>
<bean id="service" class="com.atguigu.spring.ref.Service">
<!-- 通过 ref 属性值指定当前属性指向哪一个 bean! -->
<property name="dao" ref="dao5"></property>
</bean>
- 设置级联属性
action为Action类对象
service 为Action类的一个属性(service为Service类的对象)
dao为Service类的一个属性(……)
……
action.service.dao.dataSource
<bean id="action" class="com.atguigu.spring.ref.Action">
<property name="service" ref="service2"></property>
<!-- 设置级联属性(了解) -->
<property name="service.dao.dataSource" value="DBCP2"></property>
</bean>
<bean id="dao2" class="com.atguigu.spring.ref.Dao">
<!-- 为 Dao 的 dataSource 属性赋值为 null, 若某一个 bean 的属性值不是 null, 使用时需要为其设置为 null(了解) -->
<property name="dataSource"><null/></property>
</bean>
<!-- 装配集合属性 -->
<bean id="user" class="com.atguigu.spring.helloworld.User">
<property name="userName" value="Jack"></property>
<property name="cars">
<!-- 使用 list 元素来装配集合属性 -->
<list>
<ref bean="car"/>
<ref bean="car2"/>
</list>
</property>
</bean>
<!-- 声明集合类型的 bean -->
<util:list id="cars">
<ref bean="car"/>
<ref bean="car2"/>
</util:list>
- 使用外部的list
- p命名空间的使用(p命名空间用以对基于XML配置方式的简化)
- 使用parent继承来继承bean的属性
<bean id="user2" class="com.atguigu.spring.helloworld.User">
<property name="userName" value="Rose"></property>
<!-- 引用外部声明的 list -->
<property name="cars" ref="cars"></property>
</bean>
<bean id="user3" class="com.atguigu.spring.helloworld.User"
p:cars-ref="cars" p:userName="Titannic"></bean>
<!-- bean 的配置能够继承吗 ? 使用 parent 来完成继承 -->
<bean id="user4" parent="user" p:userName="Bob"></bean>
<bean id="user6" parent="user" p:userName="维多利亚"></bean>
- 对上面程序中Bean的继承的几点说明
- 子Bean从父Bean中继承配置,包括Bean的属性配置
- 子Bean可以覆盖继承过来的配置
- 父Bean可以作为配置模板,也可以作为Bean的实例,若只想把父Bean作为模板,可以设置<bean>的abstract属性为true,这样Spring将不会实例化这个Bean
- 并不是
<bean>
中的所有属性都会被继承,如:autowire,abstract等属性就不会被继承。- 也可以忽略父Bean中的class属性,让子Bean指定自己的类,而共享相同的属性配置。但此时abstract必须为true
- xml配置里的Bean自动装配 (即代替ref属性):自动将其他bean装配到本bean的属性中去
- byType(根据类型自动装配): 必须保证IOC容器中与目标Bean类型一致的Bean只有唯一 一个
- byName(根据名称进行自动装配): 必须将目标Bean的名称和属性名设置得完全相同。
- 依赖Bean配置
Spring允许用户通过depends-on属性设定Bean的前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好
如果前置依赖于多个Bean,则可以通过逗号或空格的方式配置Bean的名称
2. 基于注解的方式
- classPath中扫描组件
- 组件扫描(component scanning): Spring能够从classPath下自动扫描,侦测和实例化具有特定注解的组件
- 特定组件包括:
- @Component: 基本注解,标识了一个受Spring管理的组件
- @Repository: 标识持久层组件(如数据库的DAO之类)
- @Service:标识服务层(业务层)组件
- @Controller: 标识表现层组件
- 对于扫描到的组件,Spring有默认的命名策略:1. 使用非限定性类名,第一个字母小写。2. 也可以在注解中通过value属性值标识组件的名称
- 当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明<context:component-scan>
<!-- 指定Spring IOC 容器扫描的包 -->
<context:component-scan
base-package="thread.conor.spring.beans.annotation"> </context:component-scan>
- base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中的所有类。
- 当需要扫描多个包时,可以使用逗号分隔。
- 如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern 属性过滤特定的类实例:
<context:component-scan
base-package="thread.conor.spring.beans"
resource-pattern="autowire/*.class"/>
- <context:include-filter>子节点表示所要包含的目标类
- <context:exclude-filter>子节点表示要排除在外的目标类
- <context:component-scan>下可以拥有若干个<context:include-filter>和
<context:exclude-filter>子节点
- 其中 <context:include-filter>子节点和<context:exclude-filter>子节点所支持的多种类型的过滤表达式:
类别 | 示例 | 说明 |
---|---|---|
annotation | thread.conor.XxxAnnotation | 所有标注了XxxAnnotation的类 |
assinable | thread.conor.XxxService | 所有继承或扩展了XxxService的类 |
aspectj | thread.conor..*Service+ | 所有类名以Service结束的类及继承或扩展它们的类。该类型采用AspectJ表达式进行过滤 |
regex | thread.\conor.anno..* | 所有thread.conor.anno包下的类,采用正则过滤 |
custom | thread.conor.XxxTypeFilter | 采用XxxTypeFilter通过代码的方式定义过滤规则,该类必须实现org.springframework.core.TypeFilter接口 |
网友评论