1.Spring中IOC与DI的概念
IOC的定义:控制反转,将对象的创建交给spring来完成,可以降低代码之间的耦合度,他的实现方式常见的有2种依赖注入(dependency injection)与依赖查找(dependency look)
DI:依赖注入,是IOC的一种实现方式
官网中关于依赖注入的说明:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-setter-injection
依赖注入的2种实现方式:
通过set方法注入
通过构造方法注入
目前官网中只说了有这2种方式
2.依赖注入的举例说明
set方式:
对象的依赖:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
常量的依赖:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="masterkaoli"/>
</bean>
p-namespace形式的引用(与上述的常量引用等价):
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="masterkaoli"/>
集合的依赖(不常见):
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
同理构造方式的依赖于set依赖大体相同
构造方法的对象依赖:
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</bean>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
</beans>
构造方法的常量依赖:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
构造方法可以提供根据构造方法的下标实现依赖:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
c-property实现构造方法的注入:
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<!-- traditional declaration with optional argument names -->
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="something@somewhere.com"/>
</bean>
<!-- c-namespace declaration with argument names -->
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree" c:email="something@somewhere.com"/>
总结:
set与构造方法的依赖注入主要包含常量的依赖、对象的依赖、以及p-property或c-property的依赖、以及构造方法的依赖还支持根据参数的下标注入
具体的可以参照spring官方文档
3.Spring的三种编程风格
schemal-based: 及xml格式
annotation-based:及annotation注解的方式
java-based:及通过Configuration的形式加载bean,此种方式相当于是xml形式的java代码表现
第一种XML格式编程风格:
xml中的描述如下:
编写启动类:
第二种方式:annotation编程方式
在xml中定义扫描的路劲
dao中添加注解:
Service中添加注解并添加自动注入
第三种方式:Configuration的使用
指定一个加载类:
可以发现Configuration既可以与Annotaion一起使用也可以与xml一起使用,也可以与2种同时使用
此时的启动类需要使用 AnnotationConfigApplicationContext 来加载Configuration的注解
4.Spring的自动装配
在xml文件中需要描述大量的依赖属性 property 是不是会很繁琐,而实际代码中已经明确说明了需要某个类型的类
Service中已经明确说明了需要IndexDao类型,而IndexDao类型的实现类已经在xml中定义了,很繁琐?
通过 default-autowire 可以自动装配 Service中的dao类型,此处按照类型自动装配,结果也是可以成功运行的。
如果bytype此时有2个相同类型的IndexDao肯定会报错,如下:
发现了2个类型,报错了,如此时 default-autowire="byName" 就不会报错了
xml中的自动装配 byName 是根据set方法后的属性名来匹配的,如下案列:
IndexService的字段名为 indexDao ,set方法后的名称为 indexDao1
运行,发现找不到indexDao
将xml中的indexDao改为indexDao1运行
上述的装配方式为全局的装配,也可以通过如下的方式给某个对象单独指定单独的装配方式
<bean id="service" class="com.test1.IndexService" autowire="byName">
Annotaion中的自动装配是如果是Resource是通过 字段名来匹配的,此处与xml的自动状态有区别
结果显示其是根据字段名称来匹配加载的
@Resource与@Autowired的区别
Autowired:默认按照类型匹配,如果有多个相同的类型则按照名称匹配
Resource:默认按照名称匹配,如果名称不存在按照类型匹配
Resource也可以按照类型以及名称来匹配查找
5.spring的常用作用域
singleton: 单列模式
prototype: 原型模式
如果一个单列模型的类中注入了一个prototype类型的类,那么注入的类prototype会失效也会变成单列
如上图所示IndexService为单列模式,IndexDao为prototype,IndexService注入了IndexDao,最终打印出来的IndexDao也为单列,失去了原型模式的意义
解决方式有2种:
第一种,实现ApplicationContextAware接口,引入ApplicationContext
第二种方式,通过Lookup主动的去寻找