- spring分層架構
- 表現層
- 服務層(業務層)
- 持久層
- spring核心
- ioc(控制反轉)
- 1)接下來是程式碼示例:
- 2)ioc容器的使用過程
- 3)ioc中的bean管理
- 4)例項化bean的三種方式
- aop(面向切面開發)
- ioc(控制反轉)
- 定義
- 優勢
- AOP底層原理
- AOP相關的術語
- AOP入門
- aop註解開發
- aop純註解開發
- Di(依賴注入)
- 1)屬性的set方法注入值的方式
- 2)構造方法賦值的方法
- 多配置檔案
- Di(依賴注入)
spring分層架構
-
表現層
springmvc
-
服務層(業務層)
spring ioc
-
持久層
mybatis
mybatis plus
hibernite
網際網路專案,多ssm結構
spring核心
-
ioc(控制反轉)
ioc將物件的建立權利交給spring框架,底層實際上是使用反射實現的。降低程式的耦合度
1)接下來是程式碼示例:
-
建立一個空的maven專案
-
引入一些基本依賴
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
-
準備實體類
// 建立一個介面 public interface UserService { public void hello(); } // 建立一個實體類 public class UserServiceImpl implements UserService { @Override public void hello() { System.out.println("Hello, world!"); } }
-
準備配置檔案
<?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="us" class="實體類的路徑"></bean> </beans>
-
在test中測試
// 常規方法 @Test public void testUser() { // TODO: write test cases for UserService UserService userService = new UserServiceImpl(); userService.hello(); } // 基於ioc容器管理的方法,ioc是一個map key是物件的標識,value是ioc建立的物件 @Test public void run1() { // 建立spring ioc工廠 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); // 獲取bean UserService userService = (UserService) ac.getBean("us"); userService.hello(); }
上面就是一個關於ioc容器的示例
2)ioc容器的使用過程
ApplicationContext介面,這個工廠介面,使用這個介面就可以獲得相應的Bean物件,該物件下有兩個實現類
- ClassPathXmlApplicationContext:載入類路徑下的spring配置檔案(常用)
- FileSystemXmlApplicationContext:載入本地磁碟下的spring配置檔案(讓專案和配置檔案分離管理,不常用)
3)ioc中的bean管理
- id屬性:bean的別名,取名要求:必須要字母開頭,可以使用數字,連字元,下劃線,字母,不能出現特殊字元
- class屬性:bean物件的全路徑
- scope屬性: bean物件的作用範圍
- singleton:單例(預設)生命週期和配置檔案一樣
- prototype:多例,不是載入配置檔案時建立,而是在獲取例項物件時建立
- request: 多例,不常用,應用於web專案中,每個請求都會建立一個新的例項物件
- session:多例,不常用,應用於web專案中,向一個http session中共享一個例項
- init-method:bean物件建立時可以配置一個指定的方法自動呼叫
- destory-method:bean物件銷燬時可以配置一個指定的方並自動呼叫
4)例項化bean的三種方式
-
預設是無參的構造方法
<bean id="us" class="實體類的路徑"></bean>
-
靜態工廠例項化方法(好處是可以自己編寫業務邏輯)
準備一個靜態工廠類
public class StaticFactory { public static UserService createUser() { // 編寫業務邏輯 // ...... return new UserServiceImpl(); } }
在xml配置檔案中使用
<bean id="us1" class="com.qc.util.StaticFactory" factory-method="createUser"></bean>
-
例項化工廠例項化方式
準備一個可以例項化的類
public class DFactory { public UserService createUser() { // 編寫業務邏輯 return new UserServiceImpl(); } }
在xml配置檔案中使用
<bean id="factory" class="com.qc.util.DFactory"></bean> <bean id="us2" factory-bean="factory" factory-method="createUser"></bean>
-
-
aop(面向切面開發)
定義
是一種編輯的正規化,是OOP的延續,也是Spring框架中函式程式設計的一種衍生正規化,利用AOP可以對業務的各個部分進行隔離,從而似的業務邏輯各部分之間的耦合度降低,提高了程式的重用性,同時提高了開發的效率,AOP採用橫向抽取機制,取代了傳統縱向繼承體系。
優勢
- 執行期間,不修改原始碼的情況下,對已有的方法進行增強,減少重複程式碼
- 提高開發效率
- 方便維護
AOP底層原理
- 如果使用介面,則使用JDK動態代理技術,如果沒有使用介面,使用的是繼承則是cglib代理
AOP相關的術語
- Joinpoint(連線點)所謂連線點是指那些被連線到的點,在spring中,這些帶點指的是方法,因為spring只支援方法型別的節點
- Pointcut(切入點)所謂切入點是我們要對哪些Joinpoint進行攔截的定義
- Advice(通知\通知)所謂通知就是指,攔截到Joinpoint之後所要做的情況就就是通知,通知分為,前置通知,後置通知,異常通知,最終通知,環繞通知(切面類中要完成的功能)
- Target(目標物件)代理的目標物件
- Weaving(織入)是指把增強應用到目標物件來建立新的代理物件的過程
- Proxy(代理)一個類被AOP織入增強後,就產生一個結果代理類
- Aspect(切面)是切入點+通知的結合,是自己編寫和配置
AOP入門
-
匯入座標依賴
<dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <!--Spring Aspects--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--aspectj--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.3</version> </dependency>
<?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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> </beans>
-
編寫spirng配置檔案中AOP的配置部分
<!-- bean管理--> <bean id="us" class="com.qc.service.impl.UserServiceImpl"/> <bean id="myAspect" class="com.qc.util.MyAspect"/> <!-- 配置aop--> <aop:config> <!-- 配置切面--> <aop:aspect ref="myAspect"> <!-- 字首通知--> <aop:before method="log1" pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/> <!-- 後置通知--> <aop:after-returning method="log2" pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/> <!-- 異常通知--> <aop:after-throwing method="log3" pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/> <!-- 最終通知--> <aop:after method="log4" pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/> <!-- 環繞通知--> <aop:around method="aroundLog" pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/> </aop:aspect> </aop:config>
import org.aspectj.lang.ProceedingJoinPoint; public class MyAspect { // 自定義切面類 = 切入點+通知 //通知 public void log1() { System.out.println("前置增強的"); } public void log2() { System.out.println("後置增強的"); } public void log3() { System.out.println("異常增強的"); } public void log4() { System.out.println("最終增強的"); } public void aroundLog(ProceedingJoinPoint point) { try { log1(); point.proceed(); // 目標方法呼叫 log2(); } catch (Throwable e) { e.printStackTrace(); log3(); } finally { log4(); } } }
注意環繞通知使用的介面
通知型別
- 前置通知:目標方法執行前進行增強
- 後置通知:目標方法執行後進行增強
- 異常通知:目標方法出現異常後進行增強
- 最終通知:目標方法無論是否異常都進行增強
- 環繞通知:目標方法執行前後,都進行增強,不過需要自己書寫
切入點表示式
- execution([修飾符] 返回值 包名.類名.方法名(引數))
- 修飾符可以省略不寫
- 返回值型別不能省略,根據方法來編寫返回值,可以用星號來代替
- 包名型別方法名是不能省略的,但是可以用星號來代替,也可以部分代替
- 引數如果是一個可以用星號來代替,如果是多個可以使用兩個點
因此比較通用的表示式:
execution( com.qc..Service.save(..))*
aop註解開發
給切面新增@Aspect,編寫增強的方法,使用通知型別註解宣告
<!-- 開啟註解掃描--> <context:component-scan base-package="com.qc"/> <!-- 開啟自動代理--> <aop:aspectj-autoproxy/>
@Aspect @Component public class MyAspect { // 自定義切面類 = 切入點+通知 //通知 @Before("execution(* com.qc.*.*.*ServiceImpl.save(..))") public void log1() { System.out.println("前置增強的"); } @AfterReturning("execution(* com.qc.*.*.*ServiceImpl.save*(..))") public void log2() { System.out.println("後置增強的"); } @AfterThrowing("execution(* com.qc.*.*.*ServiceImpl.save*(..))") public void log3() { System.out.println("異常增強的"); } @After("execution(* com.qc.*.*.*ServiceImpl.save*(..))") public void log4() { System.out.println("最終增強的"); } @Around("execution(* com.qc.*.*.*ServiceImpl.save*(..))") public void aroundLog(ProceedingJoinPoint point) { try { log1(); point.proceed(); // 目標方法呼叫 log2(); } catch (Throwable e) { e.printStackTrace(); log3(); } finally { log4(); } } }
在每個方法上使用註解進行配置,和配置檔案類似
通知型別註解:
- @Before 前置註解
- @AfterReturning 後置註解
- @AfterThrowing 異常註解
- @After 最終註解
- @Round 環繞註解
注意:在配置檔案中開啟自動代理
aop純註解開發
@EnableAspectJAutoProxy 開啟自動代理
-
Di(依賴注入)
依賴注入:在spring框架負責建立bean物件時,動態的將物件注入到其他的bean物件中
1)屬性的set方法注入值的方式
-
宣告變數並在需要依賴注入的地方設定set方法
-
在xml檔案中配置該變數的值
<bean id="us" class="com.qc.service.impl.UserServiceImpl"> <property name="userDao" ref=""></property> <property name="name" value=""></property> </bean>
引數說明:如果property中的是一個簡單型別(基本型別和字串),那麼就使用value,否則就使用ref
2)構造方法賦值的方法
-
在需要的地方新增構造方法
-
在配置檔案中使用帶引數的構造方法傳參
<bean id="userDao" class="com.qc.dao.impl.UserDaoImpl"></bean> <bean id="us" class="com.qc.service.impl.UserServiceImpl"> <constructor-arg name="userDao" ref="userDao"></constructor-arg> </bean>
-
其他型別的引數傳參
準備一個java類
public class CollectionBean { private String[] strs; private List<String> list; private Map<String, String> map; private Properties properties; public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } public Map<String, String> getMap() { return map; } public void setMap(Map<String, String> map) { this.map = map; } public String[] getStrs() { return strs; } public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } public CollectionBean() { } public void setStrs(String[] strs) { this.strs = strs; } public CollectionBean(String[] strs) { this.strs = strs; } }
-
不可變陣列
<bean id="co" class="com.qc.service.CollectionBean"> <property name="strs"> <array> <value>小美</value> <value>小張</value> <value>小王</value> </array> </property> </bean>
-
可變集合
<bean id="co" class="com.qc.service.CollectionBean"> <property name="list"> <list> <value>張三</value> <value>李四</value> <value>王五</value> </list> </property> </bean>
-
map集合
<bean id="co" class="com.qc.service.CollectionBean"> <property name="map"> <map> <entry key="name" value="zhangsan"></entry> <entry key="age" value="18"></entry> </map> </property> </bean>
-
其他型別
<bean id="co" class="com.qc.service.CollectionBean"> <property name="properties"> <props> <prop key="username">zhangsan</prop> <prop key="password">1234</prop> </props> </property> </bean>
-
-
-
多配置檔案
-
在配置檔案中使用
<import resource="applicationContext.xml"></import>
-
建立工廠時直接載入多個配置檔案
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext1.xml");
-