注入自定義對象
上一篇文章說到了注入java內(nèi)置對象的方法(Setter) 這次來說一說關(guān)于注入自定義類型對象的一些內(nèi)容
Bean和注入
定義兩個Bean如下所示:
public class User {
private String name;
private String sex;
private Role role;
}
public class Role {
private String role_name;
}
兩個Bean里面都實現(xiàn)Get()和Set()方法 并且重寫toString()方法
xml主配置文件內(nèi)使用如下配置進行測試:
<bean id="user" class="com.test.model.User">
<property name="name" value="wukong" />
<property name="sex" value="男" />
<!-- 此時name所指代的屬性 不再是簡單的數(shù)據(jù)類型 而是自定義的對象 -->
<!-- 再次使用bean標(biāo)簽來進行實例化 -->
<property name="role">
<bean id="role" class="com.test.model.Role">
<property name="role_name" value="斗戰(zhàn)勝佛" />
</bean>
</property>
</bean>
在測試文件內(nèi)(使用Junit)編寫測試方法:
@Test
public void GetUserMessige(){
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
//User指代xml文件內(nèi)的bean標(biāo)簽的id
//User.class指明User的類路徑 利用框架映射幫助我們進行實例化
User user= ac.getBean("user",User.class);
System.out.println(user);
}
控制臺輸出:
user [name=wukong, sex=男, role=role [role_name=斗戰(zhàn)勝佛]]
但是這樣的寫法 會存在這樣一個大問題:
我們在xml文件內(nèi)定義了兩個<bean> id分別為 user 和 role
但是我們只能獲取到id為user的bean內(nèi)的內(nèi)容,role我們獲取不到
進行如下測試:
xml配置文件內(nèi)容保持上述不動 在Junit測試文件內(nèi)新建測試方法 指向id為role的bean標(biāo)簽
@Test
public void GetRoleMessige(){
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
Role role= ac.getBean("role",Role.class);
System.out.println(role);
}
進行測試發(fā)現(xiàn)Junit報錯:

報錯內(nèi)容為 : No bean named 'role' available
沒有名為role的bean被定義
出現(xiàn)這個報錯的原因很好理解
==>
我們的確是定義了兩個bean
但是它們是包含與被包含的關(guān)系
role在user的內(nèi)層 其作用范圍在uesr內(nèi)
我們發(fā)出了想要越過user來直接獲取內(nèi)層bean的請求
自然是獲取不到
因此 我們在內(nèi)層的bean上設(shè)置id 其實沒有任何意義
綜上 我們還有第二種解決方案
我們將role的配置單獨書寫 并將兩個bean建立聯(lián)系
代碼如下:
<bean id="user" class="com.test.model.User">
<property name="name" value="wukong" />
<property name="sex" value="男" />
<property name="role">
<!-- 使用<ref>標(biāo)簽來使兩個獨立的bean建立聯(lián)系 -->
<ref bean="role"/>
</property>
</bean>
<bean id="role" class="com.test.model.Role">
<property name="role_name" value="斗戰(zhàn)勝佛" />
</bean>
</beans>
存在這樣一種簡寫方式:
<property name="role" ref="role"/>
<!--
name="role" 指代類中的屬性
ref="role" 指代獨立的bean的id值
-->
可以將上面配置聯(lián)系的代碼進行簡化書寫代碼
接口和注入
在開發(fā)當(dāng)中我們經(jīng)常會使用到接口 按照傳統(tǒng)的開發(fā)模式 現(xiàn)在我們有了新的包結(jié)構(gòu) 如下圖:

在正常的開發(fā)模式下 我們需要在接口的實現(xiàn)類下進行接口回調(diào) 如下圖

現(xiàn)在我們可以嘗試通過注入的方式來完成操作
在xml文件內(nèi)聲明兩個實現(xiàn)類:
<bean id="userDaoImpl" class="com.test.dao.impl.UserDaoImpl"/>
<bean id="userServiceImpl" class="com.test.service.impl.UserServiceImpl">
<!--
UserDaoImpl userdaoimpl = new UserDaoImpl();
UserDao userDao = userdaoimpl;
-->
<property name="userdao" ref="userDaoImpl"></property>
</bean>
可以看到 我們通過注入方式 利用框架幫助我們完成了接口回調(diào)的操作 具體實現(xiàn)邏輯 看上述代碼的注釋部分
此時 我們可以直接通過UsereService進行測試了:
@Test
public void 測試UserService(){
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
UserService userService= ac.getBean("userServiceImpl",UserService.class);
userService.Test01();
}
注意:
在書寫這段代碼的時候 ac.getBean("userServiceImpl",UserService.class);
雙引號括起來的地方 指向Service層bean的id
后面的類路徑 需要書寫接口的類路徑 不是接口實現(xiàn)類(impl)的類路徑
代碼提示:其實本段代碼 類似于上面所列出的User和Role的例子 不過是把實體bean轉(zhuǎn)換成了接口及其實現(xiàn)類 一點都不復(fù)雜 千萬別迷糊 hhhhh
構(gòu)造函數(shù)注入方式
在前文 我們主要使用Setter注入方式 類中只有存在set方法才能夠使用
下面我們來測試另一種注入方式:構(gòu)造函數(shù)注入
我們更改User類里面的內(nèi)容 如下:
private String name;
private String sex;
private Role role;
public User(){
System.out.println("構(gòu)造方法");
}
public void setName( String name ) {
System.out.println("setName");
this.name = name;
}
public void setSex( String sex ) {
System.out.println("setSex");
this.sex = sex;
}
public void setRole( Role role ) {
System.out.println("setRole");
this.role = role;
}
然后重寫toString()方法
重新進行測試 結(jié)果如下:

可以看到具體的流程:
現(xiàn)在我們所寫的bean標(biāo)簽的內(nèi)容 是基于java默認(rèn)為每一個類提供的無參的構(gòu)造函數(shù)
每次加載bean標(biāo)簽 都會首先去尋找所引用的類中的構(gòu)造方法 然后通過公開的Set()方法 往實例化好的對象里面添加值
所以我們每個類當(dāng)中 都要存在一個無參的構(gòu)造方法來進行控制反轉(zhuǎn)
現(xiàn)在我們添加一個有參的構(gòu)造函數(shù):
public User( String name , String sex ) {
super();
this.name = name;
this.sex = sex;
}
在xml配置文件內(nèi)添加如下代碼:
<bean id="user1" class="com.test.model.User">
<constructor-arg name="name" value="八戒"/>
<constructor-arg name="sex" value="男"/>
</bean>
新建bean標(biāo)簽做注入 <constructor-arg>標(biāo)簽對應(yīng)類中的構(gòu)造函數(shù)
因為在User類中的有參構(gòu)造函數(shù)有兩個參數(shù) 所以<constructor-arg>標(biāo)簽要寫兩個 分別對應(yīng)兩個參數(shù) 并給予初始值
此時新建測試方法:
@Test
public void 測試User構(gòu)造函數(shù)(){
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
User user= ac.getBean("user1",User.class);
System.out.println(user);
控制臺輸出:

產(chǎn)生 構(gòu)造方法 SetName 等結(jié)果
是因為我們同一個xml文件中配置了使用無參構(gòu)造函數(shù) 使用setter方式進行注入
xml文件一被加載 內(nèi)部所有的bean都會被進行實例化
別驚慌hhhh
值得注意的是 在 <constructor-arg>標(biāo)簽內(nèi)
存在index屬性 用來標(biāo)識形參的位置 起始值為1
存在type屬性 指明參數(shù)類型
如剛才我們對構(gòu)造函數(shù)進行的操作,完整內(nèi)容應(yīng)為如下:
<bean id="user1" class="com.test.model.User">
<constructor-arg name="name" index="0" type="java.lang.String" value="八戒"/>
<constructor-arg name="sex" index="1" type="java.lang.String" value="男"/>
</bean>
關(guān)于構(gòu)造函數(shù)注入自定義類型 類似于下面的語句就可以完成:
指明類中屬性 指明引用的bean(我們在上文曾新建了一個專門用來實例化Role類型的bean)
<constructor-arg name="role" ref="role" />