---
# System prepended metadata

title: Spring 框架

---

# 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


![](https://i.imgur.com/XLBFvcM.png)


### 简要分析执行流程

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範例如下
![](https://i.imgur.com/hax3ha6.png)


### 結構注入

#### 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範例如下
![](https://i.imgur.com/DJmfO7z.png)


### 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自動裝配
![](https://i.imgur.com/81nPB6l.png)



#### by type自動裝配
![](https://i.imgur.com/QJDNLKt.png)


### 註解配置
官方推薦不要再用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
![](https://i.imgur.com/HV0T0cU.png)

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

#### xml 設定
![](https://i.imgur.com/XoazKsO.png)


#### annotation設定
![](https://i.imgur.com/r42aqDq.png)

#### @Resource




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

![](https://i.imgur.com/4yDL6Xt.png)

![](https://i.imgur.com/ViE6Z6Z.png)


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>
```
路徑範例
![](https://i.imgur.com/OShKKMf.png)




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();
	}

}

```

結果
![](https://i.imgur.com/B3Sya3L.png)
