Spring Boot 之 Spring Java Config

摘要

Spring4 以后,官方推薦我們使用Java Config來代替applicationContext.xml,聲明將Bean交給容器管理。
在Spring Boot中侥袜,Java Config的使用也已完全替代了applicationContext.xml。實現(xiàn)了xml的零配置溉贿。所以無論從Spring的演進枫吧,還是學(xué)習(xí)Spring Boot的需要,都應(yīng)該深入學(xué)習(xí)Spring Java Config的使用方法宇色。這篇文章主要從以下幾個方面進行介紹:

  • Spring java Config 入門程序
  • bean標簽的使用
  • bean的依賴
  • 自動掃描
  • import 和 importResource
  • properties文件的加載及占位
  • profile

Spring Java Config入門介紹及簡單程序

回顧以前的applicationContext.xml配置方式九杂,我們會將需要使用bean通過xml的形式來配置,那么Java Config的方式宣蠕,不需要多思考例隆,就可以判斷我們應(yīng)該將bean配置在一個Java文件中,而且這個Java文件應(yīng)當(dāng)被Spring容器所識別抢蚀。我們看如下這個例子:

創(chuàng)建一個bean類
public class SomeBean {
    public void doWork() {
        System.out.println("do work...");
    }
}

其中镀层,doWork是邏輯方法。

創(chuàng)建一個Config類
@Configuration
public class Config {
    @Bean
    public SomeBean someBean() {
        return new SomeBean();
    }
}

需要注意的是皿曲,我們在config類上添加了一個@configuration的注解唱逢,見名知意,我們可以理解為Spring中的配置類屋休。在返回值為SomeBeansomeBean方法上我們添加了一個@Bean注解坞古,也不難理解,返回的new SomeBean對象將交由Spring容器進行管理劫樟。

測試
public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        SomeBean sb = context.getBean(SomeBean.class);
        sb.doWork();
    }
}

這里痪枫,我們創(chuàng)建了一個AnnotationConfigApplicationContext對象,傳入了Config.class后叠艳,得到了SomeBean對象奶陈。

do work...

以上就是Spring Java Config 配置bean的最簡單的程序,對不喜歡xml配置的開發(fā)人員還是比較有優(yōu)勢的附较。
我們知道尿瞭,在xml中,一般是這樣配置的:

<bean id="someBean" class="com.springboot.javaconfig.SomeBean" initMethod="init" destroyMethod="destroy" ref="otherBean" scope="singlon"

一個完整的bean配置包括了 id,class,initMethod,destroyMethodref,scope翅睛。

那么声搁,在Java Config如何配置這些屬性呢?其實也是很簡單的捕发,我們修改第一個例子的代碼:

public class SomeBean {

    private void init() {
        System.out.println("init...");
    }

    public void doWork() {
        System.out.println("do work...");
    }

    private void destroy() {
        System.out.println("destroy...");
    }

}

增加了init,destroy方法疏旨。

@Configuration
public class Config {

    @Bean(initMethod = "init",destroyMethod = "destroy")
    public SomeBean someBean() {
        return new SomeBean();
    }
}

在bean注解上,屬性指向?qū)?yīng)的方法名扎酷。

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        SomeBean sb1 = context.getBean(SomeBean.class);
        System.out.println(sb1);

        SomeBean sb2 = context.getBean(SomeBean.class);
        System.out.println(sb2);
        context.close();
    }
}

輸出結(jié)果為:

init...
com.spring.SomeBean@16022d9d
com.spring.SomeBean@16022d9d
destroy...

從這個程序我們可以看出如下信息:

  • init,destroy方法都在相應(yīng)的階段被調(diào)用
  • 兩次創(chuàng)建的SomeBean實例指向同一個地址檐涝,說明Spring容器給我們創(chuàng)建的SomeBean對象時單例的。
其它

如果希望創(chuàng)建了一個多例的bean,可以這樣書寫:

@Scope("prototype")
public class SomeBean {
}

如果希望使用id和class共同查找bean,可以這樣書寫:

SomeBean sb = context.getBean("someBean",SomeBean.class);

需要特別注意的是法挨,Spring默認使用Config中的函數(shù)名作為該bean的id谁榜。

bean的依賴

在xml中,我們使用value來配置注入簡單值凡纳,ref來配置注入其他對象窃植,那么在Java Config中如何實現(xiàn)呢?我們來繼續(xù)編寫代碼:

新建一個bean類
public class OtherBean {

}
修改SomeBean和Config類
public class SomeBean {

    @Autowired
    private OtherBean otherBean;

    public void sayHello() {
        System.out.println(otherBean);
    }

}
@Configuration
public class Config {

    @Bean
    public SomeBean someBean() {
        return new SomeBean;
    }

    @Bean
    public OtherBean otherBean () {
        return new OtherBean();
    }
}

此時荐糜,我們將OtherBean納入spring容器進行管理巷怜,在SomeBean類中對OtherBean的實例進行注入。得到結(jié)果:

com.spring.OtherBean@51b279c9

由此暴氏,實現(xiàn)了Java Config中的依賴注入延塑,只不過也就是將需要依賴的bean也加入Config類用bean以修飾。
當(dāng)然答渔,我們也可以不使用@AutoWired標簽关带,而通過set方法注入。


@Configuration
public class Config {

    @Bean
    public SomeBean someBean(OtherBean otherBean) {
        SomeBean someBean = new SomeBean();
        // 1
        someBean.setOtherBean(new OtherBean());
        // 2
        someBean.setOtherBean(otherBean());

        // 3
        someBean.setOtherBean(otherBean);
        return someBean;
    }

    @Bean
    public OtherBean otherBean () {
        return new OtherBean();
    }
}

set注入方法比較多沼撕,可以自行創(chuàng)建一個OtherBean對象宋雏,因為都在Config類中,也可以調(diào)用otherBean()方法端朵,也可以在參數(shù)列表中進行傳入好芭,參數(shù)名要使用OtherBean的方法名。因為OtherBean類型的可能有多個對象冲呢。

Java Config 和 注解配置混用

我們知道舍败,spring為我們提供了諸如@component,@controller,@service,@repositroy這類標簽,它們增加了類的語義敬拓,然后將對應(yīng)的類加入到了spring容器進行管理邻薯,也是避免了在xml中去配置。將Java Config和注解配置混用是我們在日常開發(fā)中經(jīng)常使用的方式乘凸,我們來看如下代碼厕诡,模擬MVC三層架構(gòu):

LoginDAO:
@Repository
public class LoginDAO {
    public void login() {
        System.out.println("login...");
    }
}
LoginService
@Service
public class LoginService {

    @Autowired
    private LoginDao loginDao;


    public void login() {
        loginDao.login();
    }
}
LoginController
@RequestMapping("/user")
@RestController
public class LoginController {

    @Autowired
    private LoginService loginService;

    @RequestMapping(path = "/login",method = RequestMethod.POST)
    public void login() {
        loginService.login();
    }
}
Java Config
@ComponentScan(basePackages = "com.spring")
@Configuration
public class Config { 
}
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

        LoginController controller = context.getBean("loginController",LoginController.class);

        controller.login();
    }
}

輸出結(jié)果:

login...

解讀:我們并沒有將LoginDAO,LoginService,LoginController納入Config,用@Bean修飾,而是使用了注解配置营勤,在Config類中通過ComponentScan標簽灵嫌,將它們納入sping容器壹罚。通過測試, 我們發(fā)現(xiàn)寿羞,Java Config 和 注解配置的混合使用時可行的猖凛。

Java Config 和 applicationContext.xml混用

有時候,我們會遇到必須使用xml配置的情況绪穆,這時候辨泳,我們可以這樣來操作:

創(chuàng)建applicationContext.xml文件
<bean id="xmlBean" class="com.spring.XMLBean"/>
修改Config
@ImportResource("com/spring/applicationContext.xml")
@ComponentScan(basePackages = "com.spring")
@Configuration
public class Config {
}

運行結(jié)果:

com.spring.XMLBean@7bb58ca3

Config類上使用@ImportResource標簽,就可以將在xml配置的bean引入到spring容器玖院。

占位符配置

自定義datasource
public class DataSource {
    private String url;
    private String driverClass;
    private String userName;
    private String password;
    // get()
    // set()
    // constructor()
}

在xml中菠红,我們配置datasource時往往將連接信息封裝在db.properties中:

driverClass=com.mysql.jdbc.driver
url=jdbc:mysql://localhost:3306/my-database
username=root
password=root

在xml中使用占位的方式來獲取:

<context:property-placeholder location="com/spring/db.properties"/>
<bean id="dataSource" class="com.spring.DataSource">
        <property name="url" value="${url}"/>
        <property name="driverClass" value="${driverClass}"/>
        <property name="userName" value="${user}"/>
        <property name="password" value="${password}"/>
</bean>
測試
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        DataSource dataSource = context.getBean("dataSource",DataSource.class);
        System.out.println(dataSource);
    }
}

輸出結(jié)果:

DataSource{url='jdbc:mysql://localhost:3306/test', driverClass='com.mysql.jdbc.driver', userName='root', password='root'}

那么如何在Config中解讀占位配置呢难菌?繼續(xù)編寫代碼:

以示區(qū)分试溯,我們修改一下,db.properties:
driverClass=com.mysql.jdbc.driver
url=jdbc:mysql://localhost:3306/test
user=admin
password=admin
修改Config
//@ImportResource("com/spring/applicationContext.xml")
@PropertySource("com/spring/db.properties")
@ComponentScan(basePackages = "com.spring")
@Configuration
public class Config {

    @Autowired
    private Environment env;

    @Bean
    public DataSource dataSource() {
        return new DataSource(env.getProperty("url"),env.getProperty("driverClass"),
                env.getProperty("user"),env.getProperty("password"));
    }
}

此時扔傅,我們先是去掉了@ImportResource標簽耍共,因為已經(jīng)不需要在xml中配置了,又使用了一個新的標簽@PropertySource猎塞,來加載db,properties文件试读,然后又注入了一個env對象,Environment類繼承了PropertyResolver接口荠耽,專門用來解析properties钩骇。

輸出結(jié)果:

DataSource{url='jdbc:mysql://localhost:3306/test', driverClass='com.mysql.jdbc.driver', user='admin', password='admin'}

可以看到,加載properties文件铝量,在Spring Java Config也提供了支持倘屹。

Profile

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市慢叨,隨后出現(xiàn)的幾起案子纽匙,更是在濱河造成了極大的恐慌,老刑警劉巖拍谐,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烛缔,死亡現(xiàn)場離奇詭異,居然都是意外死亡轩拨,警方通過查閱死者的電腦和手機践瓷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亡蓉,“玉大人晕翠,你說我怎么就攤上這事】潮簦” “怎么了淋肾?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵硫麻,是天一觀的道長。 經(jīng)常有香客問我樊卓,道長庶香,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任简识,我火速辦了婚禮,結(jié)果婚禮上感猛,老公的妹妹穿的比我還像新娘七扰。我一直安慰自己,他們只是感情好陪白,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布颈走。 她就那樣靜靜地躺著,像睡著了一般咱士。 火紅的嫁衣襯著肌膚如雪立由。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天序厉,我揣著相機與錄音锐膜,去河邊找鬼。 笑死弛房,一個胖子當(dāng)著我的面吹牛道盏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播文捶,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼荷逞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了粹排?” 一聲冷哼從身側(cè)響起种远,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎顽耳,沒想到半個月后坠敷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡斧抱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年常拓,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辉浦。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡弄抬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宪郊,到底是詐尸還是另有隱情掂恕,我是刑警寧澤拖陆,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站懊亡,受9級特大地震影響依啰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜店枣,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一速警、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鸯两,春花似錦闷旧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至钝侠,卻和暖如春该园,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背帅韧。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工里初, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弱匪。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓青瀑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親萧诫。 傳聞我的和親對象是個殘疾皇子斥难,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容