xml文件導(dǎo)入其他xml文件配置
如果我們?cè)趕pring框架中配置了多個(gè)xml文件,我們可以在讀取配置文件的時(shí)候把這些xml文件一下全都讀取,也可以只讀一個(gè)總的xml文件,在這個(gè)總的xml文件中把其他的xml全都都導(dǎo)入進(jìn)來(lái)。
例如:
student.xml文件:
<bean name="student" class="com.briup.bean.Student">
<property name="id">
<value>25</value>
</property>
</bean>
teacher.xml文件:
<bean name="teacher" class="com.briup.bean.Teacher">
<property name="student" ref="student"></property>//ref=""手動(dòng)注入哪個(gè)bean
</bean>
import.xml文件:
<import resource="teacher.xml"/>
<import resource="student.xml"/>
main:
String[] path = {"com/briup/ioc/imp/import.xml"};
ApplicationContext container = new ClassPathXmlApplicationContext(path);
Teacher t = (Teacher) container.getBean("teacher");
System.out.println(t.getStudent());
創(chuàng)建bean實(shí)例的方式
xml文件中有bean的配置,而且這個(gè)bean所對(duì)應(yīng)的java類中存在一個(gè)無(wú)參構(gòu)造器,那么這個(gè)時(shí)候spring容器就可以使用反射調(diào)用無(wú)參構(gòu)造器來(lái)創(chuàng)建實(shí)例了
通過(guò)工廠類獲得實(shí)例(工廠類實(shí)現(xiàn)了接口FactoryBean<?>)
注意spring中的PropertyPlaceholderConfigurer類的使用,在htmlsingle中直接搜索類名即可
例如:
工廠類實(shí)現(xiàn)指定接口并且實(shí)現(xiàn)接口中的三個(gè)抽象方法:
public class ConnectionFactory implements FactoryBean<Connection>{
private String driver;
private String url;
private String username;
private String password;
@Override
public Connection getObject() throws Exception {
Class.forName(driver);
Connection conn =
DriverManager.getConnection(url,username,password);
return conn;
}
@Override
public boolean isSingleton() {//判斷它是否是單例
// TODO Auto-generated method stub
return false;
}
@Override
public Class<Connection> getObjectType() {
// TODO Auto-generated method stub
return Connection.class;
}
set/get
....
}
xml文件:
因?yàn)檫@個(gè)類是一個(gè)工廠類,所以我們用名字conn在容器中拿對(duì)象的時(shí)候,拿到并不是這個(gè)工廠類對(duì)象,而是這個(gè)工廠類對(duì)象調(diào)用完工廠方法后所返回的對(duì)象.
<bean name="conn" class="com.briup.ioc.factory.ConnectionFactory">
<property name="driver">
<value>${driver}</value>//從一個(gè)配置文件中以key—value的形式拿value
</property>
<property name="url">
<value>${url}</value>
</property>
<property name="username">
<value>${username}</value>
</property>
<property name="password">
<value>${password}</value>
</property>
</bean>
<!--
下面配置的這個(gè)類,可以自動(dòng)的幫我們?nèi)プx取指定的properties文件的
內(nèi)容,文件中用key-value的形式存放數(shù)據(jù),讀完之后我們就可以用
${key}這種形式去拿文件中的value值了。
classpath指的是從src下面找.
-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:oracle.properties</value>
</property>
</bean>
main:
String path = "com/briup/ioc/factory/factory.xml";
ApplicationContext container =
new ClassPathXmlApplicationContext(path);
Connection conn = (Connection) container.getBean("conn");
System.out.println(conn);
通過(guò)實(shí)例工廠獲得實(shí)例(不需要實(shí)現(xiàn)或者繼承任何接口或者父類)
注意spring中的PropertyPlaceholderConfigurer類的使用,在htmlsingle中直接搜索類名即可
例如:一個(gè)普通的工程類
public class ConnectionFactory{
private String driver;
private String url;
private String username;
private String password;
public Object getConnection() throws Exception {
Class.forName(driver);
Connection conn = DriverManager.getConnection(url,username,password);
return conn;
}
get/set
....
}
xml文件:
<bean name="factory" class="com.briup.ioc.instanceFactory.ConnectionFactory">
<property name="driver">
<value>${driver}</value>
</property>
<property name="url">
<value>${url}</value>
</property>
<property name="username">
<value>${username}</value>
</property>
<property name="password">
<value>${password}</value>
</property>
</bean>
<!--
將來(lái)通過(guò)這個(gè)conn來(lái)拿對(duì)象,拿到的是名字為factory的工廠類調(diào)用完
名字為getConnection方法之后所返回的對(duì)象。
-->
<bean name="conn" factory-bean="factory" factory-method="getConnection"></bean>
<!-- 讀取properties文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:oracle.properties</value>
</property>
</bean>
main:
String path = "com/briup/ioc/instanceFactory/instanceFactory.xml";
ApplicationContext container =
new ClassPathXmlApplicationContext(path);
Connection conn = (Connection) container.getBean("conn");
System.out.println(conn);
通過(guò)靜態(tài)工廠獲得實(shí)例
例如:含義靜態(tài)方法的工廠類
public class ConnectionFactory{
private static String driver = "oracle.jdbc.driver.OracleDriver";
private static String url = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
private static String username = "briup";
private static String password = "briup";
public static Object getConnection() throws Exception {
Class.forName(driver);
Connection conn = DriverManager.getConnection(url,username,password);
return conn;
}
}
xml文件:
<!-- 這樣配置一定要求getConnection方法是靜態(tài)方法 -->
<bean name="conn" class="com.briup.ioc.staticFactory.ConnectionFactory" factory-method="getConnection"></bean>
main:
String path = "com/briup/ioc/staticFactory/staticFactory.xml";
ApplicationContext container = new ClassPathXmlApplicationContext(path);
Connection conn = (Connection) container.getBean("conn");
System.out.println(conn);
自定義屬性編輯器 PropertyEditor
Spring中我們可以使用屬性編輯器來(lái)將特定的字符串轉(zhuǎn)換為對(duì)象 :String-->object java.beans.PropertyEditor(JDK中的接口)用于將xml文件中字符串轉(zhuǎn)換為特定的類型
同時(shí)JDK為我們提供一個(gè)實(shí)現(xiàn)類java.beans.PropertyEditorSupport
Spring在注入時(shí),如果遇到類型不一致(例如需要Address類型但是用戶傳了個(gè)String)則會(huì)去調(diào)用相應(yīng)的屬性編輯器進(jìn)行轉(zhuǎn)換.
spring會(huì)調(diào)用屬性編輯器的setAsText(String str)進(jìn)行處理用戶傳的字符串,并調(diào)用getValue()方法獲取處理后得到的對(duì)象,所以我們?cè)诖a中處理完后記得調(diào)用setValue方法,要不然spring調(diào)用getValue方法拿不到你處理后的對(duì)象
自定義屬性編輯器示例:
-
//自定義編輯器類
public class AddressEditor extends PropertyEditorSupport { @Override public String getAsText() { return super.getAsText(); } -
//Spring遇到數(shù)據(jù)類型不一致并且不能自己處理的時(shí)候會(huì)調(diào)用這個(gè)方法處理字符串
@Override public void setAsText(String text) throws IllegalArgumentException { String[] str = text.split(","); String city = str[0]; String street = str[1]; String country = str[2]; Address add = new Address(city, street, country); setValue(add); } } //Address類 public class Address { private String city; private String street; private String country; set/get ..... } //Student類 public class Student { private long id; private String name; private boolean gender; private int age; private Address address; get/set ... }
xml文件:
<!-- 這個(gè)配置指明哪個(gè)類型對(duì)應(yīng)哪個(gè)自定義編輯器 -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="com.briup.ioc.proEdit.Address" value="com.briup.ioc.proEdit.AddressEditor"/>
</map>
</property>
</bean>
<!-- spring發(fā)現(xiàn)address的值不能注入的時(shí)候(類型不對(duì)),就會(huì)調(diào)用對(duì)應(yīng)的屬性編輯器處理了 -->
<bean id="student" class="com.briup.ioc.proEdit.Student">
<property name="id" value="1"/>
<property name="name" value="tom"/>
<property name="age" value="45"/>
<property name="gender" value="true"/>
<property name="address">
<value>kunshan,xueyuan,China</value>
</property>
</bean>
自定義事件
在spring中我們可以自定義事件,并且可以使用ApplicationContext類型對(duì)象(就是spring容器container)來(lái)發(fā)布這個(gè)事件,事件發(fā)布之后,所有的ApplicaitonListener(監(jiān)聽(tīng)器)實(shí)例都會(huì)被觸發(fā)并調(diào)用指定方法onApplicationEvent()來(lái)處理.
例如:
自定義事件類RainEvent:
public class RainEvent extends ApplicationEvent {
public RainEvent(Object source) {
super(source);
}
}
監(jiān)聽(tīng)器類RainListener1
public class RainListener1 implements ApplicationListener {
//這里需要加類型判斷,如果不加類型判斷的話只要是事件發(fā)生都會(huì)執(zhí)行監(jiān)聽(tīng)器類這個(gè)
//方法,所以我們必須加上類型判斷,當(dāng)屬于我們自定義的那個(gè)類型的時(shí)候我們才進(jìn)行處理。
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof RainEvent) {
System.out.println("唐僧大喊:" + event.getSource() + "趕快收衣服嘍!");
}
}
}
監(jiān)聽(tīng)器類RainListener2
public class RainListener2 implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof RainEvent) {
System.out.println("我們:" + event.getSource() + "太好了不用上課了!");
}
}
}
xml文件:
<!-- 只需要把這倆個(gè)監(jiān)聽(tīng)器類交給spring容器管理就可以了 -->
<bean class="com.briup.ioc.event.RainListener1"></bean>
<bean class="com.briup.ioc.event.RainListener2"></bean>
main:
String path = "com/briup/ioc/event/event.xml";
ApplicationContext container = new ClassPathXmlApplicationContext(path);
//觸發(fā)條件
container.publishEvent(new RainEvent("下雨了!"));
ioc中的annotation配置
@Autowired
@Autowired默認(rèn)按照byType匹配的方式進(jìn)行注入,如果沒(méi)有一個(gè)bean的類型是匹配的則會(huì)拋異常,
如果有多個(gè)bean的類型都匹配成功了,那么再按byName方式進(jìn)行選擇@Autowired注解可以寫(xiě)在成員變量、set/ger方法、構(gòu)造器函數(shù)上面
@Autowired如果最終匹配不成功(注意一定是一個(gè)都沒(méi)有找到的情況)則會(huì)拋出異常,
但是如果設(shè)置為@Autowired(required=false),則最終匹配不成功沒(méi)有不會(huì)拋出異常。@Autowired可以結(jié)合 @Qualifier("beanName")來(lái)使用,則可以達(dá)到byName的效果
@Autowired使用后需要在xml文件加入以下配置才能生效:
<context:annotation-config/>(高版本的就不需要加 )@Resource
@Resource的作用和 @Autowired差不多,只不過(guò)@Resource是默認(rèn)先用byname,
如果找不到合適的就再用bytype來(lái)注入Resource有倆個(gè)屬性,name和type,使用name屬性則表示要byName匹配,使用type屬性則表示要byType匹配
@Resource使用后需要在xml文件加入以下配置才能生效:
<context:annotation-config/>@PostConstruct 和 @PreDestroy
單例的類是有ApplicationContext管理。所以當(dāng)ac.destory()時(shí),類也就銷毀了。
- 標(biāo)注了 @PostConstruct 注釋的方法將在類實(shí)例化后調(diào)用。
- 標(biāo)注了 @PreDestroy 的方法將在類銷毀之前調(diào)用。
- @Component
這個(gè)注釋相當(dāng)于這樣的內(nèi)容。
<bean name="student" class="com.zts.ioctest.Student" scope="prototype">
- @Component注解可以直接定義bean,而無(wú)需在xml定義。但是若兩種定義同時(shí)存在,xml中的定義會(huì)覆蓋類中注解的Bean定義。
- @Component注解直接寫(xiě)在類上面即可
- @Component有一個(gè)可選的參數(shù),用于指定 bean 的名稱:@Component("boss")
- @Component容易不指定參數(shù),則 bean 的名稱為當(dāng)前類的類名小寫(xiě)
- @Component使用之后需要在xml文件配置一個(gè)標(biāo)簽: <context:component-scan/>
- <context:component-scan base-package="com.briup.ioc.annotation" /> 可以表示spring需要檢查哪個(gè)包下的java類,看它們是否使用了 @Component注解
- @Component定義的bean默認(rèn)情況下都是單例模式的,如果要讓這個(gè)bean變?yōu)榉菃卫?可以再結(jié)合這個(gè) @Scope 注解來(lái)達(dá)到目標(biāo) @Scope("prototype")
@Component是Spring中所有bean組件的通用形式, @Repository @Service @Controller 則是 @Component的細(xì)化,用來(lái)表示更具體的用例,分別對(duì)應(yīng)了持久化層、服務(wù)層和表現(xiàn)層。但是至少到現(xiàn)在為止這個(gè)四種注解的實(shí)質(zhì)區(qū)別很小(甚至幾乎沒(méi)有),都是把當(dāng)前類注冊(cè)為spring容器中的一個(gè)bean
注意:
component-scan標(biāo)簽?zāi)J(rèn)情況下自動(dòng)掃描指定路徑下的包(含所有子包),將帶有 @Component @Repository @Service @Controller標(biāo)簽的類自動(dòng)注冊(cè)到spring容器。
對(duì)標(biāo)記了 Spring中的 @Required @Autowired @PostConstruct @PreDestroy @Resource @WebServiceRef @EJB @PersistenceContext @PersistenceUnit等注解的類進(jìn)行對(duì)應(yīng)的操作使注解生效(包含了annotation-config標(biāo)簽的作用)。