如果轉(zhuǎn)載文章請注明出處, 謝謝 !
本系列文章是學習完 Spring4.3.8 后的詳細整理, 如果有錯誤請向我指明, 我會及時更正~??
Spring4.3.8
3.4 依賴注入(DI)
控制反轉(zhuǎn),我們可以把它看作是一個概念。而依賴注入(Dependency Injection)是控制反轉(zhuǎn)的一種實現(xiàn)方法.
James Shore給出了依賴注入的定義:依賴注入就是將實例變量傳入到一個對象中去(Dependency injection means giving an object its instance variables)。
3.4.1 xml 形式
3.4.1.1 使用構(gòu)造器注入
通過參數(shù)順序, 類型等
<bean id="person" class="com.lanou.domain.Person">
<!--根據(jù)參數(shù)名稱注入-->
<constructor-arg name="name" value="大老王"/>
<!--根據(jù)索引index注入-->
<constructor-arg index="1" value="24"/>
<!--根據(jù)構(gòu)造器參數(shù)的類型-->
<constructor-arg type="java.lang.String" value="men"/>
</bean>
3.4.1.2 使用屬性 setter 方法
public class Person {
private String name;
private int age;
private String gender;
private Car car;
private List list;
private Set set;
private Map map;
private Properties properties;
private Object[] objects;
[屬性 setter 方法]
}
簡單Bean的注入
<bean name="person" class="com.lanou.domain.Person">
<!-- property 就是一個bean 的屬性
name 用來描述屬性的名稱
value 就是屬性值, 一般類型(基本類型和 String)
-->
<property name="name" value="狗蛋兒"/>
<property name="age" value="22"/>
<property name="gender" value="men"/>
</bean>
引用其他Bean
<bean name="car" class="com.lanou.domain.Car"></bean>
<bean name="person" class="com.lanou.domain.Person">
<!--spring 容器內(nèi)部創(chuàng)建的car 對象給 Person 的 car屬性賦值-->
<property name="car" ref="car"/>
</bean>
3.4.1.3 裝配 list 集合
<property name="list">
<list>
<value>list1</value>
<ref bean="car"/>
</list>
</property>
3.4.1.4 裝配 set
<property name="set">
<set>
<value>set1</value>
<ref bean="car"/>
</set>
</property>
3.4.1.5 裝配 map
<property name="map">
<map>
<entry key="m1">
<value>map1</value>
</entry>
<entry key="m2">
<ref bean="car"/>
</entry>
</map>
</property>
3.4.1.5 裝配 properties
<property name="properties">
<props>
<prop key="p1">pp1</prop>
<prop key="p2">pp2</prop>
</props>
</property>
3.4.1.6 裝配 Object[]
<property name="objects">
<list>
<value>obj1</value>
<ref bean="car"/>
</list>
</property>
3.4.2 注解 Annotation
注解的注入會在XML之前,因此后者配置將會覆蓋前者.
配置bean
3.4.2.1 @Component
@Component是所有受 Spring 管理組件的通用形式,泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。
@Component 不推薦使用。
@Component
public class Person {
}
3.4.2.2@Controller
@Controller對應表現(xiàn)層的Bean,也就是Action, 例:
@Controller
@Scope("prototype")
public class UserAction {
}
3.4.2.3 @Respository
用于標注數(shù)據(jù)訪問組件,即DAO組件
@Repository
public class UserDao {
}
3.4.2.4 @Service
用于標注業(yè)務層組件
@Service
public class UserServiceImpl {
}
對于掃描到的組件, Spring有默認的命名策略 :
1)使用非限定類名,第一個字母小寫
(UserServiceImpl -> userServiceImpl)
2)在注解中通過 value 屬性值標識組件的名稱
(通??梢詫serServiceImpl -> userService,可以將Impl拿掉,這是一個習慣)
@Service("userService")
public class UserServiceImpl {
}
(3)當在組件類上使用了特定的注解之后, 還需要在 Spring 的配置文件中聲明 <context:component-scan>:
base-package 屬性指定一個需要掃描的基類包,Spring 容器將會掃描這個基類包里及其子包中的所有類.
當需要掃描多個包時, 可以使用逗號分隔.
配置 bean 的屬性
3.4.2.5 @Autowired
使用@Autowired 注解自動裝配, @Autowired 默認按類型裝配.
可以在普通setter方法上使用@Autowired注解
public class UserServiceImpl implements UserService{
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
可以將注解應用到構(gòu)造器和字段上
public class UserServiceImpl implements UserService{
private UserDao userDao;
@Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
}
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
}
可以將注解應用到任意名稱或參數(shù)的方法上
public class UserServiceImpl implements UserService{
private UserCatalog userCatalog;
private UserDao userDao;
@Autowired
public void prepare(UserCatalog catalog, UserDao dao){
this.userCatalog = catalog;
this.userDao = dao;
}
可以把指定類型的所有Bean提供給一個數(shù)組類型, 集合類型的變量
public class UserServiceImpl implements UserService{
@Autowired
private UserCatalog[] catalogs;
}
xml 中只定義了幾個 對應bean
<bean id="userService" class="com.lanou.service.impl.UserServiceImpl"/>
<bean id="dao" class="com.lanou.dao.impl.UserDaoImpl"/>
<bean id="catalog" class="com.lanou.domain.UserCatalog"/>
@Autowired注解是按類型裝配依賴對象,默認情況下它要求依賴對象必須存在,一旦找不到對應的Bean,自動注入就會失敗。若要改變默認的策略或允許null值,可以設置它required屬性為false。
public class UserServiceImpl implements UserService{
// xml 中沒有定義UserFinder的 bean
@Autowired(required = false)
private UserFinder userFinder;
}
3.4.2.6 @Qualifier
使用@Qualifier調(diào)整基于注解的自動注入.
在指定參數(shù)上使用@Qualifier,可以縮小類型匹配的范圍,更容易為參數(shù)找到指定的Bean。
[想使用按名稱裝配,可以結(jié)合@Qualifier注解一起使用]
public class UserServiceImpl implements UserService{
@Qualifier("userD")
@Autowired
private UserDao userD;
}
對應的Bean定義如下所示。
標識值為“userDe”的Bean將會被標記為@Qualifier(“userDe”)的參數(shù)所注入:
<bean id="dao" class="com.lanou.dao.impl.UserDaoImpl">
<qualifier value="userD"/>
</bean>
如果全部使用注解, 可以在UserDaoImpl中使用Repository配置
@Repository("userDe")
public class UserDaoImpl implements UserDao{
}
3.4.2.7 @Resource
@Resource 注解和@Autowired一樣,也可以標注在字段或?qū)傩缘膕etter方法上.
@Resource注解默認按名稱裝配。
名稱可以通過@Resource的name屬性指定,如果沒有指定name屬性,
當注解標注在字段上,即默認取字段的名稱作為bean名稱尋找依賴對象;
當注解標注在屬性的setter方法上,即默認取屬性名作為bean名稱尋找依賴對象。
public class UserServiceImpl implements UserService{
@Qualifier("userD")
@Autowired
private UserDao userD;
@Resource(name = "daoU")
private UserDao userDao;
}
注: 如果沒有指定name屬性,并且按照默認的名稱找不到依賴對象時, @Resource注解會回退到按類型裝配。但一旦指定了name屬性,就只能按名稱裝配了。
3.4.2.8 @Required
@Required注解應用于Bean屬性的setter方法,如下:
public class UserServiceImpl implements UserService{
private UserDao userDao;
@Required
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
這個表明Bean的屬性值必須在配置中指定,可以通過顯示的在Bean定義中指定,也可以使用自動注入。若沒有為這個屬性指定值,那么容器會拋出一個異常。
<bean id="userService" class="com.lanou.service.impl.UserServiceImpl">
<property name="userDao" ref="dao"/>
</bean>
<bean id="dao" class="com.lanou.dao.impl.UserDaoImpl"/>
3.4.2.8 @PostConstruct & @PreDestroy
生命周期注解
之前的做法是在xml中定義init-method 和 destroy-method方法
public class User {
public User() {
System.out.println("user .. 構(gòu)造函數(shù)");
}
@PostConstruct
public void init(){
System.out.println("I'm init method using @PostConstrut....");
}
@PreDestroy
public void destroy(){
System.out.println("I'm destory method using @PreDestroy.....");
}
}
3.5 掃描
spring2.5為我們引入了組件自動掃描機制,它可以在類路徑底下尋找標注了@Component、@Service、@Controller、@Repository注解的類,并把這些類納入進spring容器中管理.
它的作用和在xml文件中使用bean節(jié)點配置組件是一樣的。要使用自動掃描機制,我們需要打開以下配置信息:
- 引入context命名空間 需要在xml配置文件中配置以下信息
- 在配置文件中添加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">
<!-- 自動掃描指定包及其子包下的所有Bean類 -->
<context:component-scan base-package="com.lanou.domain"/>
在 base-package 指明一個包, 表明自動掃描目錄 com.lanou 包及其子包中的注解,當需要掃描多個包時, 可以使用逗號分隔.
其他用法:
<!-- 通過resource-pattern指定掃描的資源 -->
<!--只掃描repository下的類-->
<context:component-scan base-package="com.lanou" resource-pattern="dao/*.class"></context:component-scan>
<!-- 不掃描repository注解的類 ??梢耘渲枚鄠€。-->
<context:component-scan base-package="com.lanou" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
<!-- 只掃描repository注解的類。可以配置多個。 -->
<context:component-scan base-package="com.lanou" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
<!-- 不掃描某個接口。可以配置多個。使用assignable類型 -->
<context:component-scan base-package="com.lanou" use-default-filters="true">
<context:exclude-filter type="assignable" expression="com.lanou.dao.UserDao"/>
</context:component-scan>
<!-- 只掃描某個接口。 -->
<context:component-scan base-package="com.lanou" use-default-filters="false">
<context:include-filter type="assignable" expression="com.lanou.dao.UserDao"/>
</context:component-scan>
3.6 Spring 的繼承
public class People {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Student extends People {
}
<bean name="people" class="com.lanou.domain.People">
<property name="name" value="111"/>
</bean>
<bean name="student" class="com.lanou.domain.Student"></bean>
public void testExtents(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
// student 打印出來的名字為 null
System.out.println(student.getName());
}
配置文件需要更改
<!-- parent 實現(xiàn)了 spring 容器內(nèi)部的繼承關(guān)系
在父類中進行賦值, 子類繼承父類內(nèi)容
-->
<bean name="people" class="com.lanou.domain.People">
<property name="name" value="111"/>
</bean>
<bean name="student" class="com.lanou.domain.Student" parent="people"></bean>
還有其他方式解決 student 的名字賦值問題么?
student 也繼承了 people 的 name setter 方法
Spring4.3.8學習[三]
Spring4.3.8學習之 與 Struts2 整合[四]
Spring4.3.8學習之與Hibernate4 整合[五]
Spring4.3.8學習之S2SH 整合[六]