Spring配置文件中的<property></property>元素所指定的屬性名和Bean實現類的Setter方法知足Sun JavaBean的屬性命名規範:xxx的屬性對應的setXxx()方法。 注意:須要知足:"變量的前兩個字母要全大寫,要麼全小寫"。不然會出現具備誤導性的錯誤。java
1.須要提供一個有參構造函數,能夠按類型匹配注入,按因此匹配注入,聯合類型和因此匹配注入,經過自身類型反射匹配注入 2.構造函數注入的問題,可能出現循環依賴的問題,致使程序沒法啓動,只要改爲屬性注入便可解決這個問題。 例子: ConstructorInject.javaweb
public class ConstructorInject { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Person person = (Person) ctx.getBean("p2"); System.out.println(person.toString()); } }
iocdemo.xmlspring
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="person" class="com.flexible.beans.Person"> <property name="userName"><value>zhangsan</value></property> <property name="userAge"><value>20</value></property> </bean> <bean id="p2" class="com.flexible.beans.Person"> <constructor-arg type="java.lang.String"><value>zhangsan</value></constructor-arg> <constructor-arg type="java.lang.Integer"><value>28</value></constructor-arg> </bean> </beans>
Person.javaexpress
public class Person { public String userName; public Integer userAge; public Person() { } public Person(String userName, Integer userAge) { this.userName = userName; this.userAge = userAge; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getUserAge() { return userAge; } public void setUserAge(Integer userAge) { this.userAge = userAge; } [@Override](https://my.oschina.net/u/1162528) public String toString() { return "Person{" + "userName='" + userName + '\'' + ", userAge=" + userAge + '}'; } }
1.非靜態的工廠 xml配置以下: <bean id="factory" class="com.flexible.factorymethod.NonStaticFactoryMethod"></bean> <bean id="p3" factory-bean="factory" factory-method="createPerson"></bean> 2.工廠代碼以下: /** * 使用非靜態的工廠 */ public class NonStaticFactoryMethod { /** * 工廠的建立方法 * [@return](https://my.oschina.net/u/556800) */ public Person createPerson(){ Person p = new Person(); p.setUserName("lisi"); p.setUserAge(20); return p; } }
測試方法以下:緩存
//非靜態的方式 ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Person person = (Person) ctx.getBean("p3"); System.out.println(person.toString());
靜態方法: xml配置以下: <bean id="p4" class="com.flexible.factorymethod.StaticMethod" factory-method="createPerson"></bean> 工廠類以下: public class StaticMethod {session
/** * 工廠的建立方法 * * [@return](https://my.oschina.net/u/556800) */ public static Person createPerson() { Person p = new Person(); p.setUserName("lisi"); p.setUserAge(20); return p; } }
測試方法: //靜態的方式 Person person2 = (Person) ctx.getBean("p3"); System.out.println(person2.toString());ide
Spring不但能夠將String,int等字面值注入Bean中,還能夠將集合,Map等類型的數據注入Bean中,還能夠注入配置文件的其餘Bean。函數
字面值標識可使用字符串表示的值,這些值能夠經過<value></value>元素注入。xml中包含5個特殊字符,分別是&,<,>,`,'。若是包含這些這些特殊字符,就須要使用<![CDATA[]]特殊標籤。測試
注意: 通常狀況下,XML解析器會忽略元素標籤內部字符串的先後空格,可是Spring卻不會忽略元素標籤內部字符串的字符串的先後空格,若是經過如下配置爲屬性注入值<property name="xx"><value> xxx xx</value></property>,那麼先後,中間的空格將會被一塊兒賦值給xx屬性。flex
xml文件以下:
<bean id="p5" class="com.flexible.beans.Person"> <property name="userName" value="wangwu"></property> <property name="userAge" value="20"></property> </bean> <bean id="h1" class="com.flexible.beans.House"> <property name="length" value="100"></property> <property name="width" value="80"></property> <property name="height" value="60"></property> <property name="person"><ref bean="p5"></ref></property> </bean>
<ref></ref>元素能夠經過如下3個屬性引用容器中的其餘Bean。 1.bean:經過該屬性能夠引用同一容器或者父容器中的Bean,這是最多見的形式 2.local:經過該屬性只能引用同一配置文件中定義的Bean,他能夠利用XML解析器自動檢驗引用的合法性,以便開發者再編寫配置時可以幾時發現並糾正配置的錯誤。 3.parent:引用父容器中的Bean,如<ref parent="car">的配置說明car的Bean是父容器中的Bean.
Bean類 public class House {
private Double length; private Double width; private Double height; private Person person; public House() { } public Double getLength() { return length; } public void setLength(Double length) { this.length = length; } public Double getWidth() { return width; } public void setWidth(Double width) { this.width = width; } public Double getHeight() { return height; } public void setHeight(Double height) { this.height = height; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } [@Override](https://my.oschina.net/u/1162528) public String toString() { return "House{" + "length=" + length + ", width=" + width + ", height=" + height + ", person=" + person + '}'; } }
測試例子:
public class BeanInjectDemo { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); House house = (House) ctx.getBean("h1"); System.out.println(house.toString()); } }
內部Bean和Java的匿名內部類類似,既沒有名字,也不能被其餘的Bean引用,只能在聲明處爲外部Bean提供實例注入。 內部Bean幾時提供了id,name,scope屬性,也會被忽略。scope默認prototype類型。
<bean id="h1" class="com.flexible.beans.House"> <property name="length" value="100"></property> <property name="width" value="80"></property> <property name="height" value="60"></property> <property name="person"> <bean id="p5" class="com.flexible.beans.Person"> <property name="userName" value="wangwu"></property> <property name="userAge" value="20"></property> </bean> </property> </bean>
若是但願給Bean的某個屬性賦值一個null,若是使用<property name="xx"><value></value></property>這樣是達不到預期的效果的,可是可使用<property name="xx"><null/></property>
javaBean代碼
public class Car { Person person = new Person(); public Car() { } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } [@Override](https://my.oschina.net/u/1162528) public String toString() { return "Car{" + "person=" + person + '}'; } }
xml配置以下:
<bean id="car" class="com.flexible.beans.Car"> <property name="person.userName" value="zhaoliu"></property> <property name="person.userAge" value="20"></property> </bean>
測試代碼:
public class CascadeDemo { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Car car = (Car) ctx.getBean("car"); System.out.println(car.toString()); } }
Favorite.java
public class Favorite { /** * List集合 */ private List<String> favoties = new ArrayList<>(); /** * map集合 */ private Map<String,String> map = new HashMap<>(); /** *property,看做是特殊的map */ private Properties properties = new Properties(); public Favorite() { } public List<String> getFavoties() { return favoties; } public void setFavoties(List<String> favoties) { this.favoties = favoties; } public Map<String, String> getMap() { return map; } public void setMap(Map<String, String> map) { this.map = map; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } @Override public String toString() { return "Favorite{" + "favoties=" + favoties + ", map=" + map + ", properties=" + properties + '}'; } }
xml配置以下:
<bean id="favorities" class="com.flexible.beans.Favorite"> <property name="favoties"> <list> <value>游泳</value> <value>足球</value> <value>籃球</value> <value>棒球</value> </list> </property> <property name="map"> <map> <entry> <key><value>k1</value></key> <value>運動</value> </entry> <entry> <key><value>k2</value></key> <value>上班</value> </entry> <entry> <key><value>k3</value></key> <value>約會</value> </entry> </map> </property> <property name="properties"> <props> <prop key="k1">value1</prop> <prop key="k2">value2</prop> <prop key="k3">value3</prop> </props> </property> </bean> <!--集合的合併--> <bean id="childFavorities" parent="favorities"> <property name="favoties"> <list merge="true"> <value>賽車</value> </list> </property> <property name="map"> <map merge="true"> <entry> <key><value>k12</value></key> <value>運動2</value> </entry> <entry> <key><value>k22</value></key> <value>上班2</value> </entry> <entry> <key><value>k32</value></key> <value>約會2</value> </entry> </map> </property> <property name="properties"> <props merge="true"> <prop key="k12">value12</prop> <prop key="k22">value22</prop> <prop key="k32">value32</prop> </props> </property> </bean>
測試代碼:
public class CollectionAttributeInject { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Favorite favorite = (Favorite) ctx.getBean("favorities"); System.out.println(favorite.toString()); Favorite childFavorities = (Favorite) ctx.getBean("childFavorities"); System.out.println(childFavorities.toString()); } }
Spring支持使用一個Bean的方法取替換另外一個Bean的方法,替換別的Bean的Bean須要實現org.springframework.beans.factory.support.MethodReplacer接口,Spring利用該接口去替換目標Bean的方法.
被替換的類的方法:
public class Boss { public House getHouse(){ House house = new House(); house.setHeight(1.0); house.setLength(2.0); house.setLength(3.0); house.setWidth(4.0); return house; } }
替換的類須要實現org.springframework.beans.factory.support.MethodReplacer接口。
public class Boss2 implements MethodReplacer{ @Override public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { House house = new House(); house.setHeight(1.01); house.setLength(2.01); house.setLength(3.01); house.setWidth(4.01); return house; } }
xml配置文件以下:
<bean id="boss1" class="com.flexible.inject.methodreplace.Boss"> <replaced-method name="getHouse" replacer="boss2"></replaced-method> </bean> <bean id="boss2" class="com.flexible.inject.methodreplace.Boss2"></bean>
父<bean></bean>主要功能是簡化子<bean></bean>的配置,因此通常聲明未abstract="true",表示這個bean不實例化爲一個對應的Bean。
例子:
xml配置以下:
<!--這裏將這個bean聲明爲abstract,代表它不會被實例化爲bean--> <bean id="parent" class="com.flexible.beans.Parent" abstract="true"> <property name="height" value="1.70"></property> <property name="weight" value="130"></property> </bean> <bean id="child" parent="parent"> <property name="height" value="1.80"></property> </bean>
Parent.java
public class Parent { private String height; private String weight; public Parent() { } public String getHeight() { return height; } public void setHeight(String height) { this.height = height; } public String getWeight() { return weight; } public void setWeight(String weight) { this.weight = weight; } @Override public String toString() { return "Parent{" + "height='" + height + '\'' + ", weight='" + weight + '\'' + '}'; } }
測試代碼:
public class RelationBean { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Parent parent = (Parent) ctx.getBean("child"); System.out.println(parent.toString()); } }
在配置中若是當前的Bean的初始化須要前置條件(即這些前置條件都得初始化徹底了才能實例化這個Bean)知足的時候,這個時候就須要使用到依賴 depends-on=""
若是須要引用到另外一個bean的id,須要使用<idref bean="xx"></idref>的方式使用,若是在同一個配置文件可使用<idref local="xx"></idref> 這樣在開發的時期就能夠辨別出錯誤。
導入其餘配置文件能夠是import,例如:
<import resource="classpath:iocdemo2.xml"></import>
低版本的Spring值支持兩種做用域,因此纔有singleton="true|false"的配置方式。Spring爲了向後兼容,依然支持這種配置方式。推薦使用的配置方式:scope="<做用域類型>"
除了以上5種Bean做用域以外,Spring支持自定義Bean的做用域。經過org.springframework.beans.factory.config.Scope接口定義做用域,再經過org.springframework.beans.factory.config.CustomScopeConfigurer這個BeanFactoryPostprocessor註冊自定義的Bean做用域。
Spring將Bean默認的做用域都是singleton,而且將實例化的Bean緩存再ApplicationContext的容器中,若是不但願實例化以開始就進行,可使用lazy-init="true"實現懶加載,可是某些特殊的狀況依然會提早加載。
scope="prototype"非單例做用域。它會將bean交給調用者,由調用者來管理bean的生命週期。
<!--從類路徑下加載Spring配置文件,classpath關鍵字特指類路徑下加載--> <!--這裏能夠多個配置文件,建議採用逗號隔開的方式--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:flexible-context.xml</param-value> </context-param> <!--負責啓動Spring容器的監聽器,他將引用上面的上下文件參數獲取Spring配置文件的地址--> <!--該監聽器在web容器啓動時自動運行,它會根據contextConfigLocation Web容器參數獲取Spring配置文件,而且啓動Spring容器。--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
正常的狀況咱們只須要咱們只須要經過ContextLoadListoner(或者ContextLoadServlet)將Web容器與Spring容器進行整合,可是若是須要使用request,session,globalSession這三個WEB相關的做用域,就須要也配置requestContextListiner(實現了ServletRequestListener監聽器接口),ContextLoadListener只是負責監聽容器的啓動和關閉。若是Spring須要request,session,globalSession的支持就須要獲取Web容器的HTTP請求事件,此時RequestContestListener就能夠實現這個需求。
配置以下:
<!--須要三大web容器做用域時須要這個配置--> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
request:請求結束後,實例就會銷燬。 session:橫跨整個HTTPSession ,Session的全部HTTP請求共享同一個實例,HTTPSession結束後,實例銷燬。 globalSession做用域:globalSession做用域累死與session做用域,只能再Portlet的Web應用種使用。Portlet規範定義了全局Session的概念,它被組成的Portlet Web應用全部子Portlet共享,若是不在Portlet Web應用的環境下,那麼globalSession==session做用域。
須要啓用<aop:scoped-proxy></aop:scoped-proxy>
通常狀況下,Spring經過反射機制利用<bean></bean>的class屬性指定實現類實例化Bean。在某些狀況下,實例化Bean的過程比較複雜,若是按照傳統的方式,須要提供大量的配置信息。配置方式收到了限制。Spring爲此提供了一個org.springframework.beans.factory.FactoryBean工廠類結論,用戶可能夠經過實現改工廠類接口定製實例化Bean的邏輯。 例子: HouseFactoryBean.java
public class HouseFactoryBean implements FactoryBean<House> { Person person; public Person getPerson() { return person; } //接受參數 public void setPerson(Person person) { this.person = person; } //實例化bean @Override public House getObject() throws Exception { House house = new House(); house.setLength(1.0); house.setWidth(2.0); house.setHeight(3.0); house.setPerson(person); return house; } //返回Hourse類型 @Override public Class<House> getObjectType() { return House.class; } //比鬧事通FactoryBean返回的Bean是singleton @Override public boolean isSingleton() { return false; } @Override public String toString() { return "HouseFactoryBean{" + "person=" + person + '}'; } }
xml配置文件
<bean id="hoursebean" class="com.flexible.beans.HouseFactoryBean"> <property name="person"> <bean id="personp" class="com.flexible.beans.Person"> <property name="userAge" value="20"></property> <property name="userName" value="zhouqi"></property> </bean> </property> </bean>
測試代碼:
public static void main(String[] args) throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); House house = (House) ctx.getBean("hoursebean"); System.out.println(house.toString()); //若是想拿到HouseFactoryBean實例,就須要 &hoursebean HouseFactoryBean houseFactoryBean = (HouseFactoryBean) ctx.getBean("&hoursebean"); System.out.println(houseFactoryBean.toString()); House object = houseFactoryBean.getObject(); System.out.println(object.toString()); }
執行結果:
House{length=1.0, width=2.0, height=3.0, person=Person{userName='zhouqi', userAge=20}} HouseFactoryBean{person=Person{userName='zhouqi', userAge=20}} House{length=1.0, width=2.0, height=3.0, person=Person{userName='zhouqi', userAge=20}}
Spring提供了四個定義Bean的註解,分別是:
1.@Repository:用於對DAO實現類進行標註
2.@Service:用於對Service實現類進行標註。
3.@Controller:用於對Controller實現類進行標註
4.@Component能夠代替上面任何一個,只不過上面這些標註有特殊的用途,能一目瞭然的看出來這個bean的用途。
Spring提供了一個Context命名空間,它提供了經過掃面類包以應用註解定義Bean的方式。 例如:<context:component-scan base-package="com.flexible"></context:component-scan>
若是但願掃描的是特定的類而非基礎包下的類,可使用resource-pattern熟悉過濾
<context:component-scan base-package="com.flexible" resource-pattern="xx/*.class"></context:component-scan>
若是還須要更加具體的過濾,如實現了xx接口的,
例如:
<context:component-scan base-package="com.flexible"> <context:include-filter type="aspectj" expression="com.flexible..*Controller+"></context:include-filter> </context:component-scan>
使用 @Autoired
@Qualifier知道注入的Bean的名稱。
對標準註解的@Resource(須要提供一個Bean的名字)和@Inject的支持。
@Scope("prototype")
在使用<bean></bean>進行配置時,能夠經過init-method和destroy-method屬性指定Bean的初始化以及容器銷燬前執行的方法。Spring從2.5開始支持JSR-250中定義的@PostConstruct和@PreDestroy註解,在Spring中他們至關於init-method和destroy-method屬性的功能,不過在使用註解時,能夠在一個Bean中定義多個@PostConstruct和@PreDestroy方法。
例子:
LifeCyleBea.java
@Component public class LifeCyleBean { private String info; @PostConstruct public void initMethod(){ System.out.println(".....this is initMethod...."); } @PreDestroy public void destroyMethod(){ System.out.println(".....this is destroyMethod...."); } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
xml配置文件開啓包掃描:
<context:component-scan base-package="com.flexible"> </context:component-scan>
測試代碼:
public class LifeCycleDemo { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); ((ClassPathXmlApplicationContext)context).destroy(); } }
執行結果: .....this is initMethod....
.....this is destroyMethod....
JavaConfig是Spring的一個子項目,旨在經過Java類的方式提供Bean的定義信息,在Spring2.0開始發佈。普通的POJO只有標註@Configuration註解,就能夠爲Spring容器提供Bean定義的信息。每一個標註了@Bean得類方法都至關於提供了一個Bean的定義信息。經過代碼進行配置要靈活點,可是配置文件配置要簡潔些。
AppConfig.java
//將一個POJO標註爲定義Bean的配置類 @Configuration public class AppConfig { //能夠給bean一個名字,還能夠配置做用域 //@Bean(name = "car") @Bean public Car getCar(){ Car car = new Car(); car.setPerson(getPerson()); return car; } @Bean public Person getPerson(){ Person person = new Person(); person.setUserName("王八"); person.setUserAge(28); return person; } }
測試代碼:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); Car car = (Car) context.getBean(Car.class); System.out.println(car.toString());
1.直接經過@Configuration類啓動Spring容器
Spring提供了一個AnnotationConfigApplicationContext類,它可以直接經過標註¥Configuration的Java啓動Spring容器。 例如:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotationConfigApplicationContext還支持經過編碼的方式加載多個@Configuration配置類,而後刷新容器應用的配置類。 例如:
ApplicationContext context = new AnnotationConfigApplicationContext(); context.register(AppConfig.class); context.register(AppConfig2.class); context.refresh()
標註了@Configuration的配置類與標註了@Component的類同樣也是一個Bean,它能夠被Spring的context:compent-scan</context:compent-scan>掃描到相應的配置類便可。 例如:
<context:component-scan base-package="com.flexible" resource-pattern="AppConfig.class">
在@Configuration配置類中能夠經過@ImportResource引入XML配置文件,在RefXmlConfig配置類中便可直接經過@Autowired引用XML配置文件定義的Bean. RefXmlConfig.java
@Configuration @ImportResource("classpath:iocdemo2.xml") public class RefXmlConfig { @Bean @Autowired public PenBox getPenBox(PenBox penBox){ return penBox; } }
PenBox.java
public class PenBox { private String markName; private String description; public PenBox() { } public String getMarkName() { return markName; } public void setMarkName(String markName) { this.markName = markName; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public String toString() { return "PenBox{" + "markName='" + markName + '\'' + ", description='" + description + '\'' + '}'; } }
測試代碼:
public class RefXmlDemo { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(RefXmlConfig.class); PenBox penBox = (PenBox) context.getBean("penBox"); System.out.println(penBox.toString()); } }
執行結果:
PenBox{markName='xxx', description='description'}