前言
Spring的IOC極大的方便了我們的程式設計,當我們需要某個物件的時候,不在需要自己去new,只要告訴Spring一聲,Spring就會把我們所需要的類準備好,就像你原來出門要穿外套時,你得先跑到衣櫃前取出衣服,然後自己穿上。現在好了,你結婚了,只要跟你的另一半說一聲,她就會心領神會,把衣服給你拿過來,然後幫你穿上,是不是感覺很爽?Spring有三種配置方法,這三種配置方式如何選擇?先看一下這三種配置方式
XML
applicationContext.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="knight" class="com.st.BraveKnight">
<constructor-arg ref="weapon"/>
</bean>
<bean id="weapon" class="com.st.Weapon">
<property name="type" value="knife"/>
</bean>
</beans>
複製程式碼
BraveKnight
public class BraveKnight {
private Weapon weapon;
public BraveKnight(Weapon weapon) {
this.weapon = weapon;
}
public Weapon getWeapon() {
return weapon;
}
}
複製程式碼
Weapon
public class Weapon {
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
複製程式碼
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BraveKnight knight = context.getBean(BraveKnight.class);
// knife
System.out.println(knight.getWeapon().getType());
context.close();
}
}
複製程式碼
這樣一個Spring專案就完成了,可以用spring的test模組,進行測試
@RunWith(SpringJUnit4ClassRunner.class)
// 多個檔案時可用locations = {"", ""}
@ContextConfiguration(locations = "classpath*:/applicationContext.xml")
public class XMLTest {
@Autowired
BraveKnight braveKnight;
@Test
public void test() {
// knife
System.out.println(braveKnight.getWeapon().getType());
}
}
複製程式碼
用XML形式可以在配置檔案中,配置我們自己寫的類和外部庫的類,Spring通過反射可以把這些類都建立出來,並由Spring管理,在你需要的時候給你
註解
BraveKnight
@Component
public class BraveKnight {
@Autowired
private Weapon weapon;
public Weapon getWeapon() {
return weapon;
}
}
複製程式碼
Weapon
@Component
public class Weapon {
@Value("knife")
// 這個值可以從外部配置檔案中通過@Value註解讀取到
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
複製程式碼
MyConfig
@Configuration
// 如果不配置掃描的路徑,預設掃描配置類所在的包及其子包下面的所有類
@ComponentScan
public class MyConfig {
}
複製程式碼
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MyConfig.class);
context.refresh();
BraveKnight knight = context.getBean(BraveKnight.class);
// knife
System.out.println(knight.getWeapon().getType());
context.close();
}
}
複製程式碼
@RunWith(SpringJUnit4ClassRunner.class)
// 從類中讀取配置
@ContextConfiguration(classes = MyConfig.class)
public class AnnotaionTest {
@Autowired
BraveKnight braveKnight;
@Test
public void test() {
// knife
System.out.println(braveKnight.getWeapon().getType());
}
}
複製程式碼
JavaConfig
在我們自己的類上,我們可以加@Component註解讓Spring來管理,如果是第三方jar包的類呢?它的類上並不會加@Component啊,如果不想用XML來生成第三方jar包的類,JavaConfig在這個時候就派上用場了,接著上面的例子,假如Weapon這個類是第三方jar包的類,則可以通過如下形式讓Spring管理
@Configuration
// 如果不配置掃描的路徑,預設掃描配置類所在的包及其子包下面的所有類
// 可以通過屬性basePackages = {""}指定掃描的包
@ComponentScan()
public class MyConfig {
// name屬性預設是方法名,自己可以指定
@Bean(name = "weapon")
public Weapon weapon() {
Weapon weapon = new Weapon();
weapon.setType("knife");
return weapon;
}
}
複製程式碼
- XML配置修改後不用重新編譯,可以用於經常切換實現類的物件
- 註解用起來非常地簡潔,程式碼量十分少,因此是專案的第一選擇
- 當需要注入程式碼不是自己維護的第三方jar包中的類時,或者需要更為靈活地注入,比如說需要呼叫某個介面,查詢資料,然後把這個資料賦值給要注入的物件,那麼這時候就需要用到Java Config
後記
說一個我在用Spring整合Storm遇到的一個有意思的問題,一般想讓外部庫的類讓Spring管理的方法,只要用XML或者JavaConfig配置即可,我專案中有一個ClassA需要繼承Storm中的一個ClassB,但是ClassB是一個抽象類,不能在XML中配置,也不能在JavaConfig中建立出來,直接在ClassA上加上@Component註解,並不能讓Spring管理ClassA,因為ClassB Spring管理不到,Spring不能管理ClassA,這樣就會導致ClassC注入失敗
@Component
public class ClassA extends ClassB {
@Autowired
ClassC classC;
}
複製程式碼
可能會有人想,直接new出來不就行了,奈何ClassC是如下形式
@Component
public class ClassC{
@Autowired
ClassD classD;
}
複製程式碼
直接new出來,ClassD就不會被Spring注入進去,怎麼辦?回頭看在啟動類,這個類也沒有被Spring管理,是怎麼取到物件的?是從context中通過getBean方法拿的,但是在其他的類中怎麼獲取到context,其實Spring提供了一系列Aware介面,只要實現這些介面,就能獲取到要東西,我們只要實現ApplicationContextAware介面,就可以獲取到context,為了方便我直接封裝了一個工具類,通過
SpringHellper.get(ClassC.class)
複製程式碼
即可獲取Spring管理的ClassC,並能在ClassA中愉快的使用了
@Component
public class SpringHelper implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
public static <T> T getBean(Class<T> requiredType) {
return context.getBean(requiredType);
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
}
複製程式碼
注意要加上Component註解,這樣在Spring啟動後這個類的context屬性就被填充進來了
參考部落格
[1]https://zhuanlan.zhihu.com/p/29938139
[2]https://www.cnblogs.com/hedongfei/p/7899775.html
歡迎關注
喜歡本文的朋友們,歡迎關注公眾號Kruskal,收看更多精彩內容