spring
Spring
Spring的兩大核心機制(IOC、IOP)
- IOC(控制反轉)/DI(依賴注入)
- AOP(面向切面編程)
IOC
- 創建一個maven工程
- 創建一個Student類
package cn.guoke1.pojo;
import lombok.Data;
@Data
public class Student {
private int id;
private String name;
private int age;
}
以前我們需要這個類時,我們需要new這個類
Student student = new Student();
student.setAge(10);
student.setId(20);
student.setName("張三");
System.out.println(student);
在使用Spring後我們將這個類交給Spring來管理,在使用時直接拿來用就可以了
- 導入Spring依賴(只需要導入spring-context)就可以了
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
- 創建一個spring.xml 用來配置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-3.0.xsd">
<bean id="student" class="cn.guoke1.pojo.Student">
<property name="name" value="張三"></property>
<property name="age" value="12"></property>
<property name="id" value="20"></property>
</bean>
</beans>
- 測試
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Student student =(Student) context.getBean("student");
System.out.println(student);
配置文件
-
通過
bean
標籤來完成對象的管理di
:對象名class
:對象的模板類(所有交給IOC容器管理的類必須又無參構造,因爲Spring底層是通過反射機制來創建對象,調用的是無參構造)
-
對象的成員變量是通過
property
標籤來完成賦值。name
:成員變量名value
:成員變量值(j基本數據類型、String類型直接賦值,如果是引用類型,不能通過value賦值)ref
:將IOC中的另一個bean賦值給當前成員變量(DI)
<bean id="student" class="cn.guoke1.pojo.Student"> <property name="name" value="張三"></property> <property name="age" value="12"></property> <property name="id" value="20"></property> <property name="teacher" ref="teacher"></property> </bean> <bean id="teacher" class="cn.guoke1.pojo.Teacher"> <property name="name" value="張老師"></property> <property name="age" value="20"></property> </bean>
使用有參函數來創建對象
<bean id="student" class="cn.guoke1.pojo.Student">
<constructor-arg name="name" value="張三"></constructor-arg>
<constructor-arg name="age" value="20"></constructor-arg>
<constructor-arg name="id" value="10"></constructor-arg>
<constructor-arg name="teacher" ref="teacher"></constructor-arg>
</bean>
<bean id="teacher" class="cn.guoke1.pojo.Teacher">
<property name="name" value="張老師"></property>
<property name="age" value="20"></property>
</bean>
在測試時可以使用
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Student student = context.getBean(Student.class);
System.out.println(student);
來獲取實例 ,但這種方法只能在xml只能有以惡一個實例
實現原理
- 讀取配置文件,解析 XML。
- 通過反射機制實例化配置文件中所配置所有的 bean。
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class ClassPathXmlApplicationContext implements ApplicationContext {
private Map<String,Object> ioc = new HashMap<String, Object>();
public ClassPathXmlApplicationContext(String path){
try {
SAXReader reader = new SAXReader();
Document document = reader.read("./src/main/resources/"+path);
Element root = document.getRootElement();
Iterator<Element> iterator = root.elementIterator();
while(iterator.hasNext()){
Element element = iterator.next();
String id = element.attributeValue("id");
String className = element.attributeValue("class");
//通過反射機制創建對象
Class clazz = Class.forName(className);
//獲取無參構造函數,創建目標對象
Constructor constructor = clazz.getConstructor();
Object object = constructor.newInstance();
//給目標對象賦值
Iterator<Element> beanIter = element.elementIterator();
while(beanIter.hasNext()){
Element property = beanIter.next();
String name = property.attributeValue("name");
String valueStr = property.attributeValue("value");
String ref = property.attributeValue("ref");
if(ref == null){
String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
Field field = clazz.getDeclaredField(name);
Method method = clazz.getDeclaredMethod(methodName,field.getType());
//根據成員變量的數據類型將 value 進行轉換
Object value = null;
if(field.getType().getName() == "long"){
value = Long.parseLong(valueStr);
}
if(field.getType().getName() == "java.lang.String"){
value = valueStr;
}
if(field.getType().getName() == "int"){
value = Integer.parseInt(valueStr);
}
method.invoke(object,value);
}
ioc.put(id,object);
}
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e){
e.printStackTrace();
} catch (NoSuchMethodException e){
e.printStackTrace();
} catch (InstantiationException e){
e.printStackTrace();
} catch (IllegalAccessException e){
e.printStackTrace();
} catch (InvocationTargetException e){
e.printStackTrace();
} catch (NoSuchFieldException e){
e.printStackTrace();
}
}
public Object getBean(String id) {
return ioc.get(id);
}
}
給 bean 注入集合
<bean id="student" class="cn.guoke1.pojo.Student">
<property name="id" value="2"></property>
<property name="name" value="李四"></property>
<property name="age" value="33"></property>
<property name="addresses">
<list>
<ref bean="address"></ref>
<ref bean="address2"></ref>
</list>
</property>
</bean>
scope 作用域
Spring 管理的 bean 是根據 scope 來生成的,表示 bean 的作用域,共4種,默認值是 singleton。
- singleton:單例,表示通過 IoC 容器獲取的 bean 是唯一的。
- prototype:原型,表示通過 IoC 容器獲取的 bean 是不同的。
- request:請求,表示在一次 HTTP 請求內有效。
- session:回話,表示在一個用戶會話內有效。
request 和 session 只適用於 Web 項目,大多數情況下,使用單例和原型較多。
prototype 模式當業務代碼獲取 IoC 容器中的 bean 時,Spring 纔去調用無參構造創建對應的 bean。
singleton 模式無論業務代碼是否獲取 IoC 容器中的 bean,Spring 在加載 spring.xml 時就會創建 bean。
Spring 的繼承
與 Java 的繼承不同,Java 是類層面的繼承,子類可以繼承父類的內部結構信息;Spring 是對象層面的繼承,子對象可以繼承父對象的屬性值。
配置:parent="student2"
<bean id="student" class="cn.guoke1.pojo.Student">
<property name="id" value="1"></property>
<property name="name" value="張三"></property>
<property name="age" value="22"></property>
<property name="addresses">
<list>
<ref bean="address"></ref>
<ref bean="address2"></ref>
</list>
</property>
</bean>
<bean id="address" class="cn.guoke1.pojo.Student">
<property name="id" value="1"></property>
<property name="name" value="科技路"></property>
</bean>
<bean id="address2" class="cn.guoke1.pojo.Student">
<property name="id" value="2"></property>
<property name="name" value="高新區"></property>
</bean>
<bean id="stu" class="com.southwind.entity.Student" parent="student2">
<property name="name" value="李四"></property>
</bean>
Spring 的繼承關注點在於具體的對象,而不在於類,即不同的兩個類的實例化對象可以完成繼承,前提是子對象必須包含父對象的所有屬性,同時可以在此基礎上添加其他的屬性。
Spring依賴
與繼承類似,依賴也是描述 bean 和 bean 之間的一種關係,配置依賴之後,被依賴的 bean 一定先創建,再創建依賴的 bean,A 依賴於 B,先創建 B,再創建 A。
Spring 的 p 命名空間
p 命名空間是對 IoC / DI 的簡化操作,使用 p 命名空間可以更加方便的完成 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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<bean id="student" class="cn.guoke1.pojo.Student" p:id="1" p:name="張三" p:age="22" p:address-ref="address"></bean>
<bean id="address" class="cn.guoke1.pojo.Student" p:id="2" p:name="李四"></bean>
</beans>