javascript
Spring基础知识和配置
Spring 框架兩大核心機制(IoC、AOP)
idea運行spring中遇到的問題參考 idea配置遇到的問題
- IoC(控制反轉)/ DI(依賴注入)
- AOP(面向切面編程)
Spring 是一個企業級開發框架,是軟件設計層面的框架,優勢在于可以將應用程序進行分層,開發者可以自主選擇組件。
MVC:Struts2、Spring MVC
ORMapping:Hibernate、MyBatis、Spring Data
如何使用 IoC
- 創建 Maven 工程,pom.xml 添加依賴
- 創建實體類 Student
- 傳統的開發方式,手動 new Student
- 通過 IoC 創建對象,在配置文件中添加需要管理的對象,XML 格式的配置文件,文件名可以自定義。
- 從 IoC 中獲取對象,通過 id 獲取。
配置文件
-
通過配置 bean 標簽來完成對象的管理。
-
id:對象名。
-
class:對象的模版類(所有交給 IoC 容器來管理的類必須有無參構造函數,因為 Spring 底層是通過反射機制來創建對象,調用的是無參構造)
-
-
對象的成員變量通過 property 標簽完成賦值。
- name:成員變量名。
- value:成員變量值(基本數據類型,String 可以直接賦值,如果是其他引用類型,不能通過 value 賦值)
- ref:將 IoC 中的另外一個 bean 賦給當前的成員變量(DI)
通過運行時類獲取 bean
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); Student student = (Student) applicationContext.getBean(Student.class); System.out.println(student);這種方式存在一個問題,配置文件中一個數據類型的對象只能有一個實例,否則會拋出異常,因為沒有唯一的 bean。
通過有參構造創建 bean
- 在實體類中創建對應的有參構造函數。
- 配置文件
給 bean 注入集合
<bean id="student" class="com.southwind.entity.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><bean id="address" class="com.southwind.entity.Address"><property name="id" value="1"></property><property name="name" value="科技路"></property> </bean><bean id="address2" class="com.southwind.entity.Address"><property name="id" value="2"></property><property name="name" value="高新區"></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 是對象層面的繼承,子對象可以繼承父對象的屬性值。
<bean id="student2" class="com.southwind.entity.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="com.southwind.entity.Address"><property name="id" value="1"></property><property name="name" value="科技路"></property> </bean><bean id="address2" class="com.southwind.entity.Address"><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。
<?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.2.xsd"><bean id="student" class="com.southwind.entity.Student" depends-on="user"></bean><bean id="user" class="com.southwind.entity.User"></bean></beans>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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd "><bean id="student" class="com.southwind.entity.Student" p:id="1" p:name="張三" p:age="22" p:address-ref="address"></bean><bean id="address" class="com.southwind.entity.Address" p:id="2" p:name="科技路"></bean></beans>Spring 的工廠方法
IoC 通過工廠模式創建 bean 的方式有兩種:
- 靜態工廠方法
- 實例工廠方法
靜態工廠方法
package com.southwind.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;@Data @AllArgsConstructor @NoArgsConstructor public class Car {private long id;private String name; } package com.southwind.factory;import com.southwind.entity.Car;import java.util.HashMap; import java.util.Map;public class StaticCarFactory {private static Map<Long, Car> carMap;static{carMap = new HashMap<Long, Car>();carMap.put(1L,new Car(1L,"寶馬"));carMap.put(2L,new Car(2L,"奔馳"));}public static Car getCar(long id){return carMap.get(id);} } <!-- 配置靜態工廠創建 Car --> <bean id="car" class="com.southwind.factory.StaticCarFactory" factory-method="getCar"><constructor-arg value="2"></constructor-arg> </bean>實例工廠方法
package com.southwind.factory;import com.southwind.entity.Car;import java.util.HashMap; import java.util.Map;public class InstanceCarFactory {private Map<Long, Car> carMap;public InstanceCarFactory(){carMap = new HashMap<Long, Car>();carMap.put(1L,new Car(1L,"寶馬"));carMap.put(2L,new Car(2L,"奔馳"));}public Car getCar(long id){return carMap.get(id);} } <!-- 配置實例工廠 bean --> <bean id="carFactory" class="com.southwind.factory.InstanceCarFactory"></bean><!-- 賠償實例工廠創建 Car --> <bean id="car2" factory-bean="carFactory" factory-method="getCar"><constructor-arg value="1"></constructor-arg> </bean>IoC 自動裝載(Autowire)
IoC 負責創建對象,DI 負責完成對象的依賴注入,通過配置 property 標簽的 ref 屬性來完成,同時 Spring 提供了另外一種更加簡便的依賴注入方式:自動裝載,不需要手動配置 property,IoC 容器會自動選擇 bean 完成注入。
自動裝載有兩種方式:
- byName:通過屬性名自動裝載
- byType:通過屬性的數據類型自動裝載
byName
<bean id="cars" class="com.southwind.entity.Car"><property name="id" value="1"></property><property name="name" value="寶馬"></property> </bean><bean id="person" class="com.southwind.entity.Person" autowire="byName"><property name="id" value="11"></property><property name="name" value="張三"></property> </bean>byType
<bean id="car" class="com.southwind.entity.Car"><property name="id" value="2"></property><property name="name" value="奔馳"></property> </bean><bean id="person" class="com.southwind.entity.Person" autowire="byType"><property name="id" value="11"></property><property name="name" value="張三"></property> </bean>byType 需要注意,如果同時存在兩個及以上的符合條件的 bean 時,自動裝載會拋出異常。
AOP
AOP:Aspect Oriented Programming 面向切面編程。
AOP 的優點:
- 降低模塊之間的耦合度。
- 使系統更容易擴展。
- 更好的代碼復用。
- 非業務代碼更加集中,不分散,便于統一管理。
- 業務代碼更加簡潔存粹,不參雜其他代碼的影響。
AOP 是對面向對象編程的一個補充,在運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面編程。將不同方法的同一個位置抽象成一個切面對象,對該切面對象進行編程就是 AOP。
如何使用?
- 創建 Maven 工程,pom.xml 添加
- 創建一個計算器接口 Cal,定義4個方法。
- 創建接口的實現類 CalImpl。
上述代碼中,日志信息和業務邏輯的耦合性很高,不利于系統的維護,使用 AOP 可以進行優化,如何來實現 AOP?使用動態代理的方式來實現。
給業務代碼找一個代理,打印日志信息的工作交個代理來做,這樣的話業務代碼就只需要關注自身的業務即可。
package com.southwind.utils;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays;public class MyInvocationHandler implements InvocationHandler {//接收委托對象private Object object = null;//返回代理對象public Object bind(Object object){this.object = object;return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(method.getName()+"方法的參數是:"+ Arrays.toString(args));Object result = method.invoke(this.object,args);System.out.println(method.getName()+"的結果是"+result);return result;} }以上是通過動態代理實現 AOP 的過程,比較復雜,不好理解,Spring 框架對 AOP 進行了封裝,使用 Spring 框架可以用面向對象的思想來實現 AOP。
Spring 框架中不需要創建 InvocationHandler,只需要創建一個切面對象,將所有的非業務代碼在切面對象中完成即可,Spring 框架底層會自動根據切面類以及目標類生成一個代理對象。
LoggerAspect
package com.southwind.aop;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component;import java.util.Arrays;@Aspect @Component public class LoggerAspect {@Before(value = "execution(public int com.southwind.utils.impl.CalImpl.*(..))")public void before(JoinPoint joinPoint){//獲取方法名String name = joinPoint.getSignature().getName();//獲取參數String args = Arrays.toString(joinPoint.getArgs());System.out.println(name+"方法的參數是:"+ args);}@After(value = "execution(public int com.southwind.utils.impl.CalImpl.*(..))")public void after(JoinPoint joinPoint){//獲取方法名String name = joinPoint.getSignature().getName();System.out.println(name+"方法執行完畢");}@AfterReturning(value = "execution(public int com.southwind.utils.impl.CalImpl.*(..))",returning = "result")public void afterReturning(JoinPoint joinPoint,Object result){//獲取方法名String name = joinPoint.getSignature().getName();System.out.println(name+"方法的結果是"+result);}@AfterThrowing(value = "execution(public int com.southwind.utils.impl.CalImpl.*(..))",throwing = "exception")public void afterThrowing(JoinPoint joinPoint,Exception exception){//獲取方法名String name = joinPoint.getSignature().getName();System.out.println(name+"方法拋出異常:"+exception);}}LoggerAspect 類定義處添加的兩個注解:
- @Aspect:表示該類是切面類。
- @Component:將該類的對象注入到 IoC 容器。
具體方法處添加的注解:
@Before:表示方法執行的具體位置和時機。
CalImpl 也需要添加 @Component,交給 IoC 容器來管理。
package com.southwind.utils.impl;import com.southwind.utils.Cal; import org.springframework.stereotype.Component;@Component public class CalImpl implements Cal {public int add(int num1, int num2) {int result = num1+num2;return result;}public int sub(int num1, int num2) {int result = num1-num2;return result;}public int mul(int num1, int num2) {int result = num1*num2;return result;}public int div(int num1, int num2) {int result = num1/num2;return result;} }spring.xml 中配置 AOP。
<?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:aop="http://www.springframework.org/schema/aop"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd "><!-- 自動掃描 --><context:component-scan base-package="com.southwind"></context:component-scan><!-- 是Aspect注解生效,為目標類自動生成代理對象 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>context:component-scan 將 com.southwind 包中的所有類進行掃描,如果該類同時添加了 @Component,則將該類掃描到 IoC 容器中,即 IoC 管理它的對象。
aop:aspectj-autoproxy 讓 Spring 框架結合切面類和目標類自動生成動態代理對象。
- 切面:橫切關注點被模塊化的抽象對象。
- 通知:切面對象完成的工作。
- 目標:被通知的對象,即被橫切的對象。
- 代理:切面、通知、目標混合之后的對象。
- 連接點:通知要插入業務代碼的具體位置。
- 切點:AOP 通過切點定位到連接點。
總結
以上是生活随笔為你收集整理的Spring基础知识和配置的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea配置Spring遇到的问题(Lo
- 下一篇: SpringMVC+Mybatis基础知