Spring介紹
框架:高度抽取可重用代碼的一種設計;高度的通用性;
多個可重用模塊的集合,形成某個領域的整體解決方案
Spring框架:容器:可以管理所有的組件;IOC和AOP
IOC(容器):Iversion Of Control 控制反轉
用容器來整合框架
控制:資源的獲取
- 主動式(自己用什麼資源就創建new)
- 被動式(資源的獲取交給容器創建和設置)
容器:從主動的new資源爲被動的接受資源
DI(Dependency Injection):依賴注入(是IOC思想的具體實現)。容器能知道那個組件運行的時候,需要另一個組件,容器通過反射的形式,將容器中的準備好的對象注入(利用反射給屬性賦值)到最初的那個組件中。
容器中對象的創建在容器創建的時候就創建了。
一個bean對應一個對象
同一個組件在ioc中是單例的。
javabean的屬性名是由getter/setter方法決定的,去掉set之後將首字母小寫之後得到的字符串就是屬性名。
配置文件:
bean的創建原理
bean的創建就是框架利用反射new出來的bean實例
話說反射是一種效率很低的方法,所以有哪些對象是應該使用bean來創建的呢?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="stu1" class="com.onezero.Student">
<property name="name" value="張三"></property>
<property name="age" value="18"></property>
</bean>
<bean id="stu2" class="com.onezero.Student">
<property name="name" value="李四"></property>
<property name="age" value="19"></property>
</bean>
<bean id="stu3" class="com.onezero.Student">
<constructor-arg name="age" value="20"></constructor-arg>
<constructor-arg name="name" value="onezero"></constructor-arg>
</bean>
<bean id="stu4" class="com.onezero.Student">
<constructor-arg value="馬雲"></constructor-arg>
<constructor-arg value="40"></constructor-arg>
</bean>
</beans>
在配置文件中使用property標籤是通過set方法來賦值的。通過constructor-arg可以調用有參構造器賦值。若是嚴格按照有參構造器中參數出現的順序寫屬性,則可以省略name。
若沒有嚴格按照構造器中給出的參數數據賦值,可以通過index指定賦給第幾個參數。
若是構造器進行了重載且參數個數一樣,如果想省略name需要指定type(即參數類型)
綜上所述,不省略name是一種比較常見的配置方法。
通過p命名空間爲bean賦值
通過get/set方法進行賦值
<?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.xsd">
<bean id="stu05" class="com.onezero.Student" p:age="19" p:name="小紅"></bean>
</beans>
獲取bean對象的三種方法:
//通過bean的id獲取bean的實例
public void dmeo() {
ApplicationContext ac = new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("ioc配置完成");
Student stu1 = (Student) ac.getBean("stu1");
System.out.println(stu1);
}
//通過bean的類型從IOC容器中獲取bean的實例,優點是可以不用進行類型轉換,缺點是若配置文件中存在多個該類型的bean,就會報錯
public void demo2(){
Student stu = ac.getBean(Student.class);
System.out.println(stu);
}
//改進
Student stu = ac.getBean("stu1",Student.class);
通過配置文件進行復雜的賦值:
package com.onezero;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Student {
private String name;
private Integer age;
private Car car;
private List<Book> list;
private Map<String,Object> map;
private Set<Integer> set;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
", list=" + list +
", map=" + map +
", set=" + set +
", properties=" + properties +
'}';
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public Set<Integer> getSet() {
return set;
}
public void setSet(Set<Integer> set) {
this.set = set;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
private Properties properties;
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public List<Book> getList() {
return list;
}
public void setList(List<Book> list) {
this.list = list;
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
System.out.println("有參");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Student() {
System.out.println("對象被創建了");
}
}
<?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"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<bean id="stu" class="com.onezero.Student">
<property name="age" value="19"></property>
<property name="name">
<null></null>
</property>
<!--ref:引用外部bean,是嚴格的引用-->
<property name="car" ref="car"></property>
<property name="list">
<!--爲list賦值-->
<list>
<!--內部bean無法被外部獲取到-->
<bean class="com.onezero.Book" p:name="西遊記" p:author="吳承恩" p:price="20"></bean>
<!--使用外部引用-->
<ref bean="book1"></ref>
</list>
</property>
<property name="map">
<map>
<entry key="book" value-ref="book1"></entry>
<entry key="name" value="小紅"></entry>
<entry key="num">
<value>126</value>
</entry>
</map>
</property>
<property name="set">
<set>
<value>15</value>
<value>15</value>
<value>155</value>
</set>
</property>
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
<bean id="car" class="com.onezero.Car">
<property name="branch" value="寶馬"></property>
<property name="price" value="300000"></property>
</bean>
<bean id="book1" class="com.onezero.Book" p:price="30" p:author="金魚醬" p:name="人間告白">
</bean>
</beans>
通過util命名空間創建集合類型的bean,方便引用
<!--util:map相當於new了一個LinkedHashMap-->
<util:map id="map">
<entry key="book" value-ref="book1"></entry>
<entry key="name" value="小紅"></entry>
<entry key="num">
<value>126</value>
</entry>
</util:map>
<bean id="stu2" class="com.onezero.Student">
<property name="map" ref="map"></property>
</bean>
級聯屬性
級聯屬性:屬性的屬性(例如:car.price)
parent屬性
parent:指定當前的bean的配置信息繼承於哪個bean
abstract=“true”
abstract=“true”:表示當前bean的配置是一個抽象的,不能獲取它的實例,只能被繼承
depends-on:bean之間的依賴
bean 裏面的依賴只是指bean的創建順序罷了。若是沒有依賴,創建順序按照在配置文件中的書寫順序。若是有了依賴關係,那麼先創建被依賴的bean(被依賴的bean可以是有多個)
bean的作用域
bean的作用域指bean是否是單實例的。默認情況下,bean是單實例的。
scope=“prototype”:多實例
- 容器啓動時默認不去創建多實例的bean
- 獲取的時候這個bean纔會創建
- 每次獲取都創建一個新的對象
scope=“singleton”:單實例(默認)
- 在容器啓動完成之前就創建好了對象,保存到容器
- 獲取到的bean一直是一樣的
靜態工廠和實例工廠
工廠模式:工廠幫我們創建對象。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用一個共同的接口來指向新創建的對象。
- 靜態工廠:工廠本身不用創建對象,通過靜態方法調用
- factory-method:使用靜態工廠中的那個方法
- 實例工廠:工廠本身需要創建對象
- factory-bean:指定使用哪個工廠
- factory-method:使用靜態工廠中的那個方法
<!--靜態工廠方法創建bean-->
<bean id="stu1" class="com.onezero.factory.StaticFactory" factory-method="getStudent">
<constructor-arg value="李四"></constructor-arg>
</bean>
<!--實例工廠創建bean-->
<bean id="stuFactory" class="com.onezero.factory.InstanceFactory"></bean>
<bean id="stu2" class="com.onezero.Student" factory-bean="stuFactory" factory-method="getStudent">
<constructor-arg value="張三"></constructor-arg>
</bean>
-
FactoryBean是Spring的一個接口,只要是這個接口的實現類,Spring就認爲這是個工廠類
步驟:寫一個實現類;在spring中配置
public class MyFactory implements FactoryBean<Book> { @Override public Book getObject() throws Exception { System.out.println("創建一個實例"); Book book=new Book(); return book; } @Override public Class<?> getObjectType() { return Book.class; } }
FactoryBean:獲取的時候才創建實例;ioc啓動的時候不會創建實例
bean的生命週期
單實例的bean容器啓動時就創建好,容器關閉就會銷燬創建的bean
多實例bean獲取是纔會創建。
在spring中也可以通過方法來指定生命週期。
單例bean的生命週期:構造器–初始化方法–(容器關閉)銷燬方法
多例bean的生命週期:(獲取bean)構造器–初始化方法 就算是容器關閉也不會調用銷燬方法
<bean id="book" class="com.onezero.Book" init-method="init" destroy-method="destory" scope="prototype"></bean>
private ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("ioc5.xml");
//ApplicationContext接口中沒有close方法
bean的後置處理器
後置處理器:可以在bean的初始化前後調用方法。
使用步驟:實現 BeanPostProcessor接口;在配置文件中註冊
public class BeanPostProcessorTest implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+":將要調用初始化方法.這個bean是"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return null;
}
}
<bean id="beanPostProcessor" class="com.onezero.test.BeanPostProcessorTest"></bean>
引用外部屬性文件
數據庫連接池作爲單實例是最好的,一個項目就一個連接池。
<context:property-placeholder location="classpath:durid.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${usernameH}"></property>
<property name="password" value="${password}"></property>
<property name="url" value="${url}"></property>
<property name="driverClassName" value="${driver}"></property>
</bean>
因爲username是Spring中的關鍵字,所以在.properties時不能使用username,可以改爲jdbc.username
自動裝配
autowired(xml)
- byType
- byName
- constructor
通過註解@Autowored實現自動裝配,它可以用於成員變量、構造器及方法,不過只能用於裝配引用。
SpEL:Spring Expression Language
#{}
${}
//調用靜態方法
#{T(全類名).方法}
通過註解將bean加入容器
- @Component
- @Repository:持久層
- @Controller:控制層
- @Service:業務層
之後要在xml中加入
<context:component-scan base-package=""/>
Spring 會掃描所有base-package下的類。