IOC 与依赖注入
IOC:控制反转:将对象的创建权,由Spring管理.
DI(依赖注入):在Spring创建对象的过程中,把对象依赖的属性注入到类中。
bean的配置规则:
1、在 xml 文件中通过 bean 节点来配置 bean,基本格式如下:
<bean id="helloWorld"class="com.wangning.spring.HelloWorld"scope="singleton | prototype"init-method="init"destory-method="destory"> <!-- 为属性赋值 --> <property name="user"value="wangning" ></property> </bean>
属性解释:
id: 一个Bean可以通过一个id属性惟一指定和引用 class:指定这个Bean所关联的类是那个类,需要使用全类名。 scope:实例化的模式。singleton(默认 单例模式) prototype(非单例模式) init-method:初始化方法 destory-metho:销毁方法
2、对于spring配置一个bean时,如果需要给该bean提供一些初始化参数,则需要通过依赖注入方式,所谓的依赖注入就是通过spring将bean所需要的一些参数传递到bean实例对象的过程。
2.1、使用属性的setter注入:
属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象。属性注入使用 <property> 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 <value> 子节点指定属性值。
<bean id="……"class="……"> <!-- name 为bean中定义的属性名字 --> <property name="属性1"value="……"/> <property name="属性2"value="……"/> …… </bean> <bean id="helloWorld"class="com.wangning.spring.HelloWorld"> <!-- 为属性赋值 --> <property name="user"value="wangning"></property> <property name="password"value="1234"></property> </bean>
ps:使用属性的setter注入方式时,所注入的属性必须提供setter和getter方法,spring在实例化时会自动调用无参数的构造方法或者静态工厂方法,实例化之后自动调用属性的set方法将值设置进去。
2.2、使用构造器注入:
通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用。构造器注入在 <constructor-arg> 元素里声明属性, <constructor-arg> 中没有 name 属性。
<bean id="……"class="……"> <constructor-arg>构造函数需要的参数1</constructor-arg> <constructor-arg>构造函数需要的参数2</constructor-arg> …… </bean> <bean id="helloWorld"class="com.wangning.spring.HelloWorld"> <constructor-arg>"wangning"</constructor-arg> <constructor-arg>"1234"</constructor-arg> …… </bean>
ps:使用构造器注入方式时:spring在实例化该Bean时会调用配置参数符合的构造方法。前提是在对应的class中提供相应的构造器。如果不存在对应的构造器,将报错。
3、注入依赖bean
组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能,要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用。
在 Bean 的配置文件中, 可以通过 <ref> 元素或 ref 属性为 Bean 的属性或构造器参数指定对 Bean 1的引用。也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 Bean
<!-- bean2中通过bean1属性引用了bean1 --> <beans> <bean id="bean1"class="……"> <property name="属性1"value="……"/> …… </bean> <bean id="bean2"class="……"> <property name="bean1"ref="bean1"/> …… </bean> </beans>
ps: ref 和 value 只能存在一个。直接赋值用value 引用对象用ref
4、集合注入
当需要给Bean的集合引用注入值时,spring也提供了相应的标签。
在标签里包含一些元素. 这些标签可以通过 <value> 指定简单的常量值, 通过 <ref> 指定对其他 Bean 的引用。也可以通过<bean> 指定内置 Bean 定义,通过 <null/> 指定空元素. 甚至可以内嵌其他集合。
4.1、Set集合注入
<bean id="……"class="……"> <set> <value>value1</value> <value>value2</value> …… </set> </bean> <bean id="user"class="com.wangning.spring.User"> <property name="userName"value="wangning"></property> <!-- users在类文件中为一个Set表 --> <property name="users"> <!-- 使用 set 元素来装配集合属性 set不能有相同的对象 --> <!-- 使用 value元素来赋值 --> <value>user1</value> <value>user2</value> <!-- 使用 ref 元素来赋值需要在之前配置好user1和user2的Bean --> <set> <ref bean="user1"/> <ref bean="user2"/> </set> </property> </bean>
4.2、List集合(和数组)注入
数组的定义和 List 一样, 都使用 <list>
<bean id="……"class="……"> <list> <value>value1</value> <value>value2</value> …… </list> </bean> <bean id="user"class="com.wangning.spring.User"> <property name="userName"value="wangning"></property> <!-- users在类文件中为一个List表 --> <property name="users"> <!-- 使用 list元素来装配集合属性 list能有相同的对象 --> <list> <!-- 使用 value元素来赋值 --> <value>user1</value> <value>user2</value> <!-- 使用 ref 元素来赋值需要在之前配置好user1和user2的Bean --> <ref bean="user1"/> <ref bean="user2"/> </list> </property> </bean>
4.3、Map集合注入
通过 <map> 标签定义, <map> 标签里可以使用多个 <entry> 作为子标签,每个条目包含一个键和一个值。
因为键和值的类型没有限制, 所以可以自由地为它们指定 <value>, <ref>, <bean> 或 <null> 元素。
可以将 Map 的键和值作为 <entry> 的属性定义: 简单常量使用 key 和 value 来定义; Bean 引用通过 key-ref 和 value-ref 属性定义。
<bean id="……"class="……"> <map> <entry key="key1"value="value1"> <entry key="key2"value="value2"> …… </map> </bean> <bean id="user"class="com.wangning.spring.User"> <map> <!--简单常量 --> <entry key="user1"value="wangning"> <entry key="user2"value="wang"> …… <!--bean引用 -- 使用 ref 元素来赋值需要在之前配置好user1和user2的Bean> <entry key-ref="user1"value="wangning"> <entry key-ref="user2"value="wang"> ..... 或者 <entry key-ref="user1"value-ref="user1"> <entry key-ref="user2"value-ref="user2"> ...... </map> </bean>
4.4、.Properties注入
资源文件通过 <props> 标签定义, <props> 标签里可以使用多个 <prop> 作为子标签,每个条目包含一个键和一个值。
<bean id="……"class="……"> <props> <prop key="key1">value1</prop> <prop key="key2">value2</prop> …… </props> </bean>
ps:Spring 会自动根据数据类型转换,支持泛型
5、使用 - -取出数据
package com.wangning.bean; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.Iterator; import java.util.Map; /** * Created with IntelliJ IDEA. * User: WangNing * Date: 2017/10/16 * Time: 19:02 * To change this template use File | Settings | File Templates. * Description: */ public class test { @Test public void quchu(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:user.xml"); User user = (User) applicationContext.getBean("user"); // 通过list集合取出数据 System.out.println("**********通过list集合取出数据*****"); for(User u : user.getUserList()){ System.out.println("name="+u.getName()+" "+u.getId()); } // 通过set集合取出数据 System.out.println("**********通过set集合取出数据*****"); for(User u : user.getUserSet()){ System.out.println("name="+u.getName()); } // 通过map集合取出数据 迭代器 System.out.println("*******通过map集合取出数据 迭代器****"); Map<String,User> users = user.getUserMap(); Iterator it=users.keySet().iterator(); while(it.hasNext()){ String key=(String) it.next(); User user1=users.get(key); System.out.println("key="+key+" "+user1.getName()); } // 通过map集合取出数据 Entry System.out.println("*******通过map集合取出数据 简洁方法****"); for(Map.Entry<String,User> entry1:user.getUserMap().entrySet()){ System.out.println(entry1.getKey()+" "+entry1.getValue().getName()); } } }
6、 对象的自动注入
<!-- autowire : 自动注入 (注入属性值,对象) --> <!-- default: 继承最上方的autowire 头文件 beans里面设置--> byName:根据名字注入 byType:根据类型注入 no:不适用自动注入 constructor:构造器注入 == bytype(可以没getter setter方法) qutodetctect:byName和byType中间 自动转换
自动装配与注解注入
基于xml的自动装配
配有三种模式:byTpye(根据类型),byName(根据名称)、constructor(根据构造函数)。
1、在byTpye模式中,Spring容器会基于反射查看bean定义的类,然后找到与依赖类型相同的bean注入到另外的bean中,这个过程需要借助setter注入来完成,因此必须存在set方法,否则注入失败。
基于xml的配置如下,通过使用<bean>的autowire属性启动名称为userService的自动装配功能
测试代码:
2、byName模式的自动装配,此时Spring只会尝试将属性名与bean名称进行匹配,如果找到则注入依赖bean。
3、constructor模式,在该模式下Spring容器同样会尝试找到那些类型与构造函数相同匹配的bean然后注入。
基于注解的自动装配(@Autowired&@Resource&@Value)
基于@Autowired注解的自动装配
@Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用标注到成员变量时不需要有set方法,请注意@Autowired 默认按类型匹配的
上述代码我们通过3种方式注入userDao实例,xml配置文件只需声明bean的实例即可,在实际开发中,我们只需选择其中一种进行注入操作即可,建议使用成员变量注入,这样可以省略set方法和构造方法,相当简洁。
默认情况下@Autowired是按类型匹配的(byType),如果需要按名称(byName)匹配的话,可以使用@Qualifier注解与@Autowired结合
基于@Resource注解的自动装配
@Resource,默认按 byName模式 自动注入。
可以标注在成员变量和set方法上,但无法标注构造函数。@Resource有两个中重要的属性:name和type。Spring容器对于@Resource注解的name属性解析为bean的名字,type属性则解析为bean的类型。因此使用name属性,则按byName模式的自动注入策略,如果使用type属性则按 byType模式自动注入策略。倘若既不指定name也不指定type属性,Spring容器将通过反射技术默认按byName模式注入。
基于@Value注解的自动装配以及properties文件读取
@Value接收一个String的值,该值指定了将要被注入到内置的java类型属性值,放心,不必关系类型转换,大多数情况下Spring容器都会自动处理好的。一般情况下@Value会与properties文件结合使用。
使用注解向Spring注入Bean
在类上增加了一个注解Component,在类的开头使用了@Component注解,它可以被Spring容器识别,启动Spring后,会自动把它转成容器管理的Bean。
以上的声明方式与之前在xml声明bean的效果相同。
同时还可给@Component、@Service和@Repository输入一个String值的名称,如果没有提供名称,那么默认情况下就是一个简单的类名(第一个字符小写)变成Bean名称。
除了@Component外,Spring提供了3个功能基本和@Component等效的注解,分别对应于用于对DAO,Service,和Controller进行注解。
1:@Repository 用于对DAO实现类进行注解。
2:@Service 用于对业务层注解,但是目前该功能与 @Component 相同。
3:@Constroller用于对控制层注解,但是目前该功能与 @Component 相同。
@Configuration 和@Bean
@Configuration注解标明BeanConfiguration类,使得BeanConfiguration类替代了xml文件,也就是说注解@Configuration等价于<beans>标签。在该类中,每个使用注解@Bean的公共方法对应着一个<bean>标签的定义,即@Bean等价于<bean>标签。