閱讀本篇需要讀者首先對(duì)Spring注解配置Bean部分的內(nèi)容有粗淺的了解
Spring注解配置Bean的兩種主要方式
Spring4開始可以為子類注入子類對(duì)應(yīng)的泛型類型成員變量的引用
在此通過一個(gè)實(shí)例來(lái)說明如何通過Spring的注解實(shí)現(xiàn)
- 主程序依賴于抽象類型
- 向子類所對(duì)應(yīng)的泛型類類型成員變量中注入其他對(duì)象的引用(此處為向UserService的成員變量中注入對(duì)UserRepository類型的對(duì)象的引用)
為了便于讀者理解品腹,先說點(diǎn)題外話岖食,討厭咬文嚼字的朋友可以選擇跳過,這里我所理解的依賴和注入舞吭,二者是分開的泡垃。依賴一方面只的是類型與類型之間的依賴關(guān)系析珊,另一方面是指最后主程序與主程序main方法中所使用的類之間的依賴關(guān)系。很明顯蔑穴,前者主要是抽象類AbstractService 對(duì) AbstractRepository的依賴關(guān)系忠寻,不過這個(gè)關(guān)系進(jìn)而被子類繼承成為UserService對(duì)UserRepository的依賴關(guān)系,為什么說這個(gè)依賴關(guān)系被繼承了呢存和?
很明顯奕剃,main()方法中本來(lái)只對(duì)UserService類的方法進(jìn)行了調(diào)用,但卻間接地調(diào)用了UserRepository的方法并得到了其方法的輸出結(jié)果捐腿,顯然調(diào)用前者方法的同時(shí)也調(diào)用了后者的方法纵朋,這表明UserService類對(duì)UserRepository類是有依賴關(guān)系的,而這依賴關(guān)系在這兩個(gè)類自己的代碼中沒有體現(xiàn)茄袖,很顯然是從父類型那繼承得到的
而主程序這邊很明顯操软,并沒有直接使用UserService類和UserRepository類的相關(guān)方法,而僅僅得到了AbstractService的對(duì)象也只調(diào)用了AbstractService的方法宪祥。所以我們的主程序是依賴于抽象類型的
另一點(diǎn)注入聂薪,指的就是資源的注入。我們是不可能直接創(chuàng)建兩個(gè)抽象類型的對(duì)象的蝗羊。
而我們的子類UserService中所使用的父類的成員變量repository它是AbstractRepository類型兼容的藏澳,但是很明顯它肯定不僅僅是AbstractRepository這個(gè)抽象類型。那它有時(shí)何時(shí)被創(chuàng)建何時(shí)又到我們所得到的這個(gè)UserService類的實(shí)例對(duì)象中來(lái)的呢耀找。答案就是我們Spring4開始才有的泛型依賴注入
后面配合代碼詳細(xì)介紹這個(gè)泛型依賴注入的過程
一.抽象類型
- 抽象類型1:AbstractService
package thread.conor.spring.generic;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class AbstractService <T>{
@Autowired
protected AbstractRepository<T> repository;
public abstract void add(T t);
}
- 抽象類型2:AbstractRepository
package thread.conor.spring.generic;
public abstract class AbstractRepository <T>{
public abstract void act(T t);
}
注意:
- 由于AbstractService 中需要有一個(gè)repository成員變量來(lái)實(shí)現(xiàn)對(duì)另一個(gè)泛型類AbstractRepository的依賴關(guān)系笆载,所以不能使用接口代替抽象類
- 上面兩個(gè)抽象類都沒有使用與特定組件相關(guān)的注解(如@Component)也就意味著無(wú)法被Spring容器通過<context:component-scan>標(biāo)簽掃描到
- @Autowired注解標(biāo)識(shí)了repository成員變量依據(jù)類型AbstractRepository的自動(dòng)裝配
二. 實(shí)體類型
- UserService
package thread.conor.spring.generic;
import org.springframework.stereotype.Service;
import thread.conor.spring.domain.User;
@Service
public class UserService extends AbstractService<User>{
@Override
public void add(User user) {
System.out.println("user " +user.getName() + " is in service");
repository.act(user);
}
}
- Repository
package thread.conor.spring.generic;
import org.springframework.stereotype.Repository;
import thread.conor.spring.domain.User;
@Repository
public class UserRepository extends AbstractRepository<User>{
@Override
public void act(User user) {
System.out.println(user.getName()+" is added into repository");
}
}
- user
package thread.conor.spring.domain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class User {
private String name = "conor";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
注意:
- 上述實(shí)體類都有與組件相關(guān)的注解(@Repository,@Service,@Component),都會(huì)被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"
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-4.0.xsd">
<context:component-scan base-package="thread.conor.spring.generic,thread.conor.spring.domain"></context:component-scan>
</beans>
<context:component-scan base-package="thread.conor.spring.generic,thread.conor.spring.domain"></context:component-scan>
此句即為配置需要掃描的包涯呻,其他外面的只是框子(套路)
四. Main主程序
package thread.conor.spring.generic;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-generic.xml");
AbstractService service = (AbstractService) ctx.getBean("userService");
service.add(ctx.getBean("user"));
}
}
注意:
- 這里main方法只使用了抽象類型AbstractService,即除了IOC容器外只有對(duì)抽象類型AbstractService的依賴(對(duì)于AbstractRepository的依賴也是通過這層依賴進(jìn)行傳遞的)
五. 運(yùn)行結(jié)果
user conor is in service
conor is added into repository
- 第一句表明主程序雖然只對(duì)抽象類型AbstractService有依賴關(guān)系腻要,卻調(diào)用了其子類的方法复罐。
- 第二句說明在調(diào)用UserService的方法
add(User user)
時(shí)也通過其中的repository.act(user);
這句話調(diào)用到了UserRepository的對(duì)象的方法act(User user)
。這里repository是從UserService父類型AbstractService繼承而來(lái)的成員變量雄家,但是這個(gè)成員變量的引用指向的卻是UserRepository類的一個(gè)對(duì)象效诅,當(dāng)然這個(gè)對(duì)象是關(guān)于AbstractRepository類兼容的,這里這個(gè)repository成員變量就是通過AbstractService抽象類中對(duì)repository成員變量標(biāo)識(shí)的@Autowired注解來(lái)將 標(biāo)識(shí)了@Repository注解的UserRepository類 的對(duì)象依據(jù)類型自動(dòng)裝配到UserService的成員變量repository之中的
這里UserService類的repository成員變量是從父類型繼承而來(lái)的趟济。