spring实战第二章小记-装配bean
时间:2020/02/06
一.思想
1.创建应用对象之间协作关系的行为通常称为装配,这也是依赖注入(DI)的本质。
对于上面这句话的个人理解:当我们在new一个对象时如果传入了别的对象作为参数(这个对象可能是引用数据类型也可能是基本数据类型),这时两个对象之间就形成了一种依赖关系,由于这种依赖关系的存在,两个对象之间就是一种强耦合的关系,而通过依赖注入可以降低两个对象之间的耦合度,注意,不是消除,如果两个对象之间没有耦合关系,那两个对象就是完全没有关系的。
2.spring框架提供了三种主要的装配机制:
- 在XML中进行显式配置
- 在Java中进行显示配置
- 隐式的bean发现机制和自动装配
3.关于上面三种方式的优先级(作者的意思,你可以根据自己的喜爱选择):
隐式的bean发现机制和自动装配>在Java中进行显示配置>在XML中进行显示装配
4.spring从两个角度来实现自动化装配:
- 组件扫描:spring会自动发现应用上下文中所创建的bean。
- 自动装配:spring自动满足bean之间的依赖。
5.自动装配:自动装配就是让spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在spring应用上下文中寻找匹配某个bean需求的其他bean。
6.在进行显式配置时,JavaConfig是更好的方案,因为它更为强大、类型安全并且对重构友好。
7.默认情况下,spring中的bean都是单例的。
8.在XML中声明DI时,会有多种可选的配置方案和风格。具体到构造器注入,有两种基本的配置方案可供选择:
- <constructor-arg>元素
- 使用spring3.0所引入的c-命名空间
9.对于DI来说,有的时候是指类型的装配——也就是将对象的引用装配到依赖于它们的其他对象之中。而有的时候,我们需要做的只是用一个字面量来配置对象(基本类型对象以及String类型对象)。
10.在装配bean引用和字面量值方面,<constructor-arg>和c-命名空间的功能是相同的。但是c-命名空间无法将集合装配到构造器参数中。
11.该选择构造器注入还是属性注入(Setter方法注入)呢?作为一个通用的规则,对强依赖使用构造器注入,而对可选择的依赖使用属性注入。
12.spring框架的核心是spring容器,整个容器中存放的东西可以看作key-value对,key是bean的id,value是bean的对象。
二.在XML中进行显示装配
1.spring的XML配置文件的根元素(最基本的约束):
<?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"> </bean>
2.使用XML来启用组件扫描,使用spring context命名空间的<context:component-scan>元素。
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="soundsystem"/>
</beans>
3.<bean>: <bean>元素类似于JavaConfig中的@Bean注解。
<bean class="sdnu.machi.one"/>
创建这个bean的类通过class属性来指定,并且要使用全限定的类名。
因为没有明确给定ID,所以这个bean将会根据全限定类名来进行命名。在上述代码中,bean的id将会是”sdnu.machi.one#0″。其中,”#0″是一个计数的形式,用来区分相同类型的其他bean。如果你声明了另外一个one,并且没有明确进行标识,那么它自动得到的id将会是”sdnu.machi.one#1″。
通常来将更好的办法是借助id属性,为每个bean设置一个你自己选择的名字。
当spring发现这个<bean>元素时,它将会调用one的默认构造器来创建bean。(如果这时没有默认构造函数会报错)。
4.<constructor-arg>: 通过该元素可以在XML中实现依赖注入。如下
<bean id="one" class="sdnu.machi.one"> <constructor-arg ref="two" /> </bean>
当spring遇到这个<bean>元素时,它会创建一个one实例。<constructor-arg>元素会告知spring要将一个id为two的bean引用传递到one的构造器中(有参构造器)。
该元素还有value属性,通过该属性表明给定的值要以字面量的形式注入到构造器中。
5.c-命名空间: 它是在XML中更为简洁的描述构造器参数的方式。要使用它的话,必须要在XML的顶部声明其模式,如下:
xmlns:c="http://www.springframework.org/schema/c"
添加了命名空间和模式声明后,我们就可以使用它来声明构造器参数了,如下所示:
<bean id="one" class="sdnu.machi.one" c:cd-ref="two"/>
除了使用构造器参数名外,我们也可以使用参数在整个参数列表中的位置信息:
c:_0-ref:"two"
将参数的名称换成了“0”,也就是参数的索引,因为在XML中不允许数字作为属性的第一个字符,因此必须要添加一个下划线作为前缀。
在这里因为只有一个构造器参数,所以我们还有另外一种方案——根部不用去标示参数:
c:_-ref="two"
如果要注入的是字面量(基本数据类型以及string类型),参考代码如下:
c:_title="machi"
c:_content="is a good boy"
title和content是参数名,也可以通过索引进行装配,如下:
c:_0="machi"
c:_1="is a good boy"
下划线后面的数字指明了参数的索引。
6.<list>: 当需要注入集合时,可以在<constructor-arg>元素中使用<list>元素来声明列表,如下:
<constructor-arg> <list> <value>machi</value> <value>is</value> <value>a</value> <value>good</value> <value>boy</value> </list> </constructor-arg>
<list>元素是<constructor-arg>的子元素,这表明一个包含值的列表将会传递到构造器中。其中,<value>元素用来指明列表中的每个元素。
我们也可以使用<ref>元素代替<value>,实现bean引用列表的装配。
<ref bean="id名“/>
7.<set>: 与<list>元素作用相同。
8.<property>: <property>元素为属性的Setter方法所提供的功能与<constructor-arg>元素为构造器所提供功能是一样的。它也有ref属性。
9.p-命名空间: 作为<property>元素的代替方案。为了启用p-命名空间,必须要在XML文件中与其他的命名空间一起对其进行声明:
xmlns:p="http://www.springframework.org/schema/p
使用方式如下:
p:compactDisc-ref="compactDisc"
示例代码:
10.<import>: 在XML中,可以使用import元素来拆分XML配置
三.在Java中进行显式装配
其实就是JavaConfig类,需要和注解一起使用。
四.隐式的bean发现机制和自动装配(基于注解的隐式装配)
1.@Component: 在类上使用@Component注解,这个简单的注解表明该类会作为组件类,并告知spring要为这个类创建bean。
默认id为将类名的第一个字母变为小写。如果不想使用默认id,可以自定义id,如@Component(“自定义id名“)。
2.@ComponentScan: 组件扫描默认是不启用的。我们需要显示配置一下spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。@ComponentScan注解能够在spring中启用组件扫描。如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包,即扫描这个包以及下面的所有子包,查找带有@Component注解的类。
为了指定不同的基础包,你所需要做的就是在@ComponentScan的value属性中指明包的名称,如@ComponentScan(”包名“)。如果你想要更加清晰地表名你所设置的是基础包,可以通过basePackages属性进行配置,如@ComponentScan(basePackeges=”包名“),如果你想要设置多个基础包,只需要将basePackages属性设置为要扫描包的一个数组即可,如@ComponentScan(basePackages={“包1”,“包2”,…..})。除了将包设置为简单的string类型之外,该注解还提供了另外一种方法,那就是将其指定为包中所包含的类或接口,如@ComponentScan(basePackageClassess={one.class, two.class}),这些类所在的包将会作为组件扫描的基础包。
3.@Named: 该注解作用与@Component基本相同。
4.@Autowired: 该注解是用来进行依赖注入的,它会寻找spring容器中适合的bean传递给该方法的参数。@Autowired注解不仅能够用在构造器上,还能用在属性的Setter方法上。实际上该注解可以用在该类的任何方法上.
不管是构造器、Setter方法还是其他的方法,spring都会尝试满足方法参数上所声明的依赖。
如果没有匹配的bean,那么在应用上下文创建的时候,spring会抛出一个异常。为了避免异常的出现,你可以将@Autowired的required属性设置为false。将required属性设置为false时,spring会尝试执行自动装配,但是如果没有匹配的bean的话,spring会让这个bean处于未装配的状态。
如果有多个bean都能满足依赖关系的话,spring将会抛出一个异常,表名没有明确指定要选择哪个bean进行装配。
5.@Inject: 该注解作用与@Autowired相同。
6.@Configuration: 创建JavaConfig类的关键在于为其添加@Configuration注解,该注解表名这个类是一个配置类。
7.@Bean: 要在JavaConfig中声明bean,我们需要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加@Bean注解。如下:
@Bean public CompactDisc sgtPeppers(){ return new SgtPeppers(); }
@Bean注解会告诉spring这个方法将会返回一个对象,该对象要注册为spring应用上下文中的bean。
默认情况下,bean的id与带有@Bean注解的方法名是一样的。在上述例子中,这个bean的id为sgtPeppers。你可以通过name属性指定一个不同的名字。@Bean(name=“id名”)。
如果你要借助JavaConfig实现注入该怎么做,通过下面这行代码可以实现注入:
@Bean public CompactDisc sgtPeppers(){ return new SgtPeppers(); } @Bean public CDPlayer cdPlayer(){ return new CDPlayer(sgtPeppers()); }
第二个bean需要注入第一个bean,所以在构造方法中调用了第一个方法。
可以看到,通过调用方法来引用bean的方法有点令人困惑。下面是一种更为简单的方法:
@Bean public CDPlayer cdPlayer(CompactDisc compactDisc){ return new CDPlayer(compactDisc); }
在这里,cdPlayer()方法请求一个CompactDisc作为参数。通过这种方法引用其他bean通常是最佳的选择,因为它不会要求将COmpactDisc声明到同一个配置之中。
8.@Import: 通过@Import注解将两个类组合在一起。
9.@ImportResource: 使配置在JavaConfig中的bean和配置在XML中的bean都会被加载到spring容器之中。
五.最后
最后想写一点与前面没有关系的东西,不久前在b站看到的了一个视频,题目叫做《不要做程序员》,本着好奇的心态就点就去了,一开始以为就是一个劝退的视频,无非就要说做程序员怎们怎们不好,但是进去后发现我错了,up主在里面说了一个很好的思想,叫:不要做程序员,要做问题解决者。对啊,编程只是解决问题的一种工具,重要的不在于工具,而是思想以及热情,我们不能被工具所累,最后只是成为了一个为了编程而编程的人,而要想一想我们所做的东西能为别人带来什么,尽量让自己的程序有所意义,这就是一点感悟吧,不喜勿喷。