前言
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>
public class BraveKnight { private Weapon weapon; public BraveKnight(Weapon weapon) { this.weapon = weapon; } public Weapon getWeapon() { return 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管理,在你需要的時候給你
注解
@Component public class BraveKnight { @Autowired private Weapon weapon; public Weapon getWeapon() { return weapon; } }
@Component public class Weapon { @Value("knife") // 這個值可以從外部配置文件中通過@Value注解讀取到 private String type; public String getType() { return type; } public void setType(String type) { this.type = type; } }
@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屬性就被填充進來了!