# Spring 框架
官方文件 路徑
https://docs.spring.io/spring-framework/docs/5.2.0.RELEASE/spring-framework-reference/
## SpringIOC
為什需要IOC :
在還沒有spring以前,所有服務耦合性很高,修改了一個服務會影響許多的服務,有了spring之後,透過spring 控制反轉,透過綁定介面,而非綁定物件,當服務使用到之後才進行注入,當服務需要修改的時候只需要抽換介面背後的實作,達到最少的修改
### 分析實現
1.先寫一個UserDao接口
```
public interface UserDao {
public void getUser();
}
```
2.再去寫Dao的實作
```
public class UserDaoImpl implemants UserDao {
@Override
public void getUser() {
System.out.println("獲取用戶數據");
}
}
```
3.然後再去寫UserService的接口
```
public interface UserService{
public void getUser();
}
```
4.最後寫Service的實現類
```
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
```
5.測試一下
```
@Test
public void test(){
UserService service = new UserServiceImpl();
service.getUser();
}
```
這是我們原來的方式 , 開始大家也都是這麽去寫的對吧 . 那我們現在修改一下 .
把Userdao的實現類增加一個 .
```
public class UserDaoMySqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySql获取用户数据");
}
}
```
緊接著我們要去使用MySql的話 , 我們就需要去service實現類里面修改對應的實現
```
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoMySqlImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
```
在假設, 我們再增加一個Userdao的實現類 .
```
public class UserDaoOracleImpl implements UserDao {
@Override
public void getUser() {
System.out.println("Oracle获取用户数据");
}
}
```
那麽我們要使用Oracle , 又需要去service實現類里面修改對應的實現 . 假設我們的這種需求非常大 , 這種方式就根本不適用了, 甚至反人類對吧 , 每次變動 , 都需要修改大量代碼 . 這種設計的耦合性太高了, 牽一發而動全身 .
那我們如何去解決呢 ?
我們可以在需要用到他的地方 , 不去實現它 , 而是留出一個接口 , 利用set , 我們去代碼里修改下
```
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 利用set實現
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
```
現在去我們的測試類里 , 進行測試 :
```
@Test
public void test(){
UserServiceImpl service = new UserServiceImpl();
service.setUserDao( new UserDaoMySqlImpl() );
service.getUser();
//那我們現在又想用Oracle去實現呢
service.setUserDao( new UserDaoOracleImpl() );
service.getUser();
}
```
以前所有東西都是由程序去進行控制創建 , 而現在是由我們自行控制創建對象 , 把主動權交給了調用者 . 程序不用去管怎麽創建,怎麽實現了 . 它只負責提供一個接口 .
這種思想 , 從本質上解決了問題 , 我們程序員不再去管理對象的創建了 , 更多的去關注業務的實現 . 耦合性大大降低 . 這也就是IOC的原型 !
## Spring MVC

### 简要分析执行流程
DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
我们假設请求的url為 : http://localhost:8080/SpringMVC/hello
如上url拆分成三部分:
http://localhost:8080服務器域名
SpringMVC部署在服務器上的web站點
hello表示控制器
通過分析,如上url表示为:请求位於服務器localhost:8080上的SpringMVC站點的hello控制器。
HandlerMapping為處理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根據请求url查找Handler。
HandlerExecution表示具体的Handler,其主要作用是根據url查找控制器,如上url被查找控制器为:hello。
HandlerExecution將解析後的信息傳遞给DispatcherServlet,如解析控制器映射等。
HandlerAdapter表示處理器適配器,其按照特定的规則去執行Handler。
Handler讓具體的Controller執行。
Controller將具體的執行信息返回给HandlerAdapter,如ModelAndView。
HandlerAdapter將視圖邏輯名或模型傳遞给DispatcherServlet。
DispatcherServlet调用視圖解析器(ViewResolver)来解析HandlerAdapter傳遞的邏輯视圖名。
視圖解析器將解析的邏輯视圖名傳给DispatcherServlet。
DispatcherServlet根據視圖解析器解析的視圖结果,调用具体的視圖。
最终視圖呈現给用戶。
## 依賴注入 Dependency Injection
### set 注入
#### 範例
#### 宣告address class
```
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
```
#### 宣告Student class
```
public class Student {
private String name;
private Address address;
private String[] book;
private List<String> hobby;
private Map<String,String> card;
private String wife;
private Properties info;
private Set<String> games;
get set ....
}
```
#### beans.xml
```
<?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="address" class="com.spring.pojo.Address">
<property name="address" value="台北市"></property>
</bean>
<bean id="student" class="com.spring.pojo.Student">
<!-- 普通注入 -->
<property name="name" value="student1"/>
<!-- bean注入 -->
<property name="address" ref="address"/>
<!-- 陣列注入 -->
<property name="book" >
<array>
<value>小紅帽</value>
<value>大野狼</value>
<value>小紅帽奶奶</value>
<value>三隻小豬</value>
</array>
</property>
<!-- list -->
<property name="hobby" >
<list>
<value>看電影</value>
<value>寫作文</value>
<value>念書</value>
<value>游泳</value>
</list>
</property>
<!-- map -->
<property name="card">
<map>
<entry key="健保卡" value="M12345567"/>
<entry key="信用卡" value="938849950005"/>
</map>
</property>
<!-- set -->
<property name="games">
<set>
<value>皇室戰爭</value>
<value>小唐人</value>
<value>仙劍奇俠傳</value>
</set>
</property>
<!-- null -->
<property name="wife">
<null/>
</property>
<!-- properties -->
<property name="info">
<props>
<prop key="driver">cars</prop>
<prop key="sex">男</prop>
</props>
</property>
</bean>
</beans>
```
### p xml注入
可以透過p:代替properties範例如下

### 結構注入
#### java Score
```
public class Score {
private String level;
private int score;
public Score(String level, int score) {
super();
this.level = level;
this.score = score;
}
}
```
#### beans.xml
```
<?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="score" class="com.spring.pojo.Score">
<constructor-arg name="level" value="A" />
<constructor-arg name="score" value="100" />
</bean>
</beans>
```
### c xml注入
可以透過c:代替constructor範例如下

### bean的作用域
| Scope | Description |
| -------- | -------- |
| singleton | (Default) Scopes a single bean definition to a single object instance for each Spring IoC container. |
| prototype | Scopes a single bean definition to any number of object instances. |
| request | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext. |
| session | Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext. |
| application | Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.|
| websocket | Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.|
### 測試自動裝配
#### 建立 persion 下有 dog cat
手動配置
```
<?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="dog" class="com.spring.pojo.Dog"/>
<bean id="cat" class="com.spring.pojo.Cat"/>
<bean id="persion" class="com.spring.pojo.Persion" >
<property name="name" value="spring-beforeautotest"/>
<property name="dog" ref="dog"/>
<property name="cat" ref="cat"/>
</bean>
</beans>
```
### 透過自動裝配將物件自動set進去
#### by name自動裝配

#### by type自動裝配

### 註解配置
官方推薦不要再用xml配置.使用註解配置
```
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
```
#### @Autowired

可以配合@Qualifier 指定對應的bean
#### xml 設定

#### annotation設定

#### @Resource
## SpringAOP
**為什麼要使用AOP:
在開發過程中,開發者有可能在各個方法中要求加入一些方法,
這些方法的代碼重複性很高,卻分散在各個方法中,AOP可以透過代理
幫我們集中處理這些方法**


maven 引入
```
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
```
applicationContext.xml
```
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="log" class="com.springAOP.log.Log" />
<bean id="userService" class="com.springAOP.service.UserService"/>
<bean id="annotationPointCut" class="springAopAnnotation.AnnotationPointCut"/>
<!-- 開啟自動代理 -->
<aop:aspectj-autoproxy/>
</beans>
```
路徑範例

classname :MethodBeforeAdvice
```
package com.springAOP.log;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class Log implements MethodBeforeAdvice{
//method 使用的方法
//target 目標物件
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println(method.getClass().getName()+"的"+method.getName()+"方法");
}
}
```
classname :UserService
```
package com.springAOP.service;
public class UserService implements UserServiceIntf{
public void add() {
System.out.println("新增");
}
public void delete() {
System.out.println("刪除");
}
public void update() {
System.out.println("修改");
}
public void select() {
System.out.println("查詢");
}
}
```
classname :UserServiceIntf
```
package com.springAOP.service;
public interface UserServiceIntf {
public void add();
public void delete();
public void update();
public void select();
}
```
classname :AnnotationPointCut
```
package springAopAnnotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointCut {
@Before(value = "execution(* com.springAOP.service.UserService.*(..))")
public void before(){
System.out.println("-----執行參數之前------");
}
}
```
測試
```
package springAOP;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.springAOP.service.UserService;
import com.springAOP.service.UserServiceIntf;
public class Test {
public static void main(String[] args) {
ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");
//接口必須是介面
UserServiceIntf userService = (UserServiceIntf)context.getBean("userService");
userService.add();
}
}
```
結果
