Spring簡介
Spring是一個輕量級的控制反轉(IoC)和面向切面(AOP)的容器(框架)。
- Spring 是一個開源的框架,為了解決企業應用開發的復雜性而創建的
- spring是一個輕量級的控制反轉(Ioc)和面向切面(AOP)的容器框架
- 從大小和開銷兩個方面而言spirng是輕量級的
- 通過控制反轉(Ioc)的技術達到松耦合的目的
- 提供了面向切面編程的豐富支持,允許通過分離應用的業務邏輯與系統級服務進行內聚性的開發
- 包含並且管理應用對象的配置和生命周期,這個意義上是一種容器
- 將簡單的組件配置,組合成為復雜的應用,這個意義上是框架
目的:解決企業應用開發的復雜性
優點:
- Spring是一個開源免費的框架(容器)
- Spring是一個輕量級的框架,非侵入式的
- 控制反轉 IoC,面向切面 AOP
- 對事物的支持,對框架的支持
組成
Spring 框架是一個分層架構,由 7 個定義良好的模塊組成。Spring 模塊構建在核心容器之上,核心容器定義了創建、配置和管理 bean 的方式。
組成 Spring 框架的每個模塊(或組件)都可以單獨存在,或者與其他一個或多個模塊聯合實現。每個模塊的功能如下:
-
核心容器
提供 Spring 框架的基本功能。
核心容器的主要組件是 BeanFactory,它是工廠模式的實現。BeanFactory 使用控制反轉(IoC)將應用程序的配置和依賴性規范與實際的應用程序代碼分開。 -
Spring 上下文
Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息,包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和調度功能。 -
Spring AOP
Spring在它的AOP模塊中提供了對面向切面編程的豐富支持。AOP允許通過分離應用的業務邏輯與系統級服務(例如安全和事務管理)進行內聚性的開發。 -
Spring DAO
該模塊對現有的JDBC技術進行了優化。可以保持數據庫訪問代碼干凈簡潔,並能防止因關閉數據庫資源失敗而引起的問題。 -
Spring ORM
Spring並沒有自己實現ORM框架,只是集成了若干個 ORM 框架,從而提供了 ORM 的對象關系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。 -
Spring Web 模塊
Web上下文模塊建立於應用上下文模塊之上,提供了一個適合於Web應用的上下文。Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工作。 -
Spring MVC 框架
Spring為構建Web應用提供了一個功能全面的MVC框架。雖然Spring可以很容易地與其它MVC框架集成,例如Struts2,但Spring的MVC框架使用IoC對控制邏輯和業務對象提供了完全的分離。
控制反轉 IoC
IoC理論推導
用我們原來的方式寫一段代碼
#1. UserDao接口
public interface UserDao {
public void getUser();
}
#2、Dao的實現類
public class UserDaoImpl implements 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的實現類,若我們要使用Oracle,又需要去service實現類里面修改對應的實現
public class UserDaoOracleImpl implements UserDao {
@Override
public void getUser() {
System.out.println("Oracle獲取用戶數據");
}
}
現在程序的耦合性太高了, 牽一發而動全身。
如何解決:利用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的原型。
IoC 和 DI
控制反轉IoC(Inversion of Control),是一種設計思想,DI(依賴注入)是實現IoC的一種方法,它是由主動的編程變成被動的接收。
IoC (Inversion of Control)是 Spring 的一種設計思想
在傳統的程序設計,我們直接在對象內部通過 new 來創建對象,是程序主動去創建依賴對象;而在 Spring 中有專門的一個容器來創建和管理這些對象,並將對象依賴的其他對象注入到該對象中,這個容器我們一般稱為 IoC 容器。所有的類的創建、銷毀都由 Spring 來控制,也就是說控制對象生存周期的不再是引用它的對象,而是 Spring,所以這叫控制反轉。
DI(Dependency Injection)依賴注入
依賴注入是指組件之間的依賴關系由容器在運行期決定,即由容器動態的將某個依賴關系注入到組件之中。依賴注入的目的並非為軟件系統帶來更多功能,而是為了提升組件重用的頻率,並為系統搭建一個靈活、可擴展的平台。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實現。
控制反轉是一種通過描述(XML或注解)並通過第三方去生產或獲取特定對象的方式。在Spring中實現控制反轉的是IoC容器,其實現方法是依賴注入(DI)。
bean
在 Spring 中,構成應用程序主干並由 Spring IoC 容器管理的對象稱為 bean。 bean 是由 Spring IoC 容器實例化,組裝和管理的對象。
bean 可以認為是那些我們想注入到 Spring IoC 容器的 Java 對象實例的抽象。
項目中我們經常會在 Service 上使用 @Service 注解,然后在要使用該 Service 的類中通過 @Autowire 注解來注入,這個 Service 就是一個 bean。
@Service 注解相當於告訴 IoC 容器:這個類你需要幫我創建和管理;而 @Autowire 注解相當於告訴 IoC 容器:我需要依賴這個類,你需要幫我注入進來。
依賴注入(DI)
- 依賴 : 指Bean對象的創建依賴於容器;Bean對象的依賴資源
- 注入 : 指Bean對象所依賴的資源,由容器來設置和裝配
依賴注入是利用set方法來進行注入的:
Hello實體類
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("Hello,"+ name );
}
}
編寫spring文件,命名為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就是java對象,由Spring創建和管理-->
<bean id="hello" class="com.ldc.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
測試
@Test
public void test(){
//解析beans.xml文件,生成管理相應的Bean對象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//getBean : 參數即為spring配置文件中bean的id .
Hello hello = (Hello) context.getBean("hello");
hello.show();
}
面向切面編程 AOP
AOP(Aspect Oriented Programming)
通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
AOP 與 OOP 相輔相成, 提供了與 OOP 不同的抽象軟件結構的視角。在 OOP 中以類(class)作為基本單元, 而 AOP 中的基本單元是 Aspect(切面)。
AOP在Spring中提供聲明式事務,同時允許用戶自定義切面。
為什么需要 AOP
場景:開發中在多個模塊間有某段重復的代碼,我們怎么處理的?
在傳統的面向過程編程中,我們將這段代碼,抽象成一個方法,然后在需要的地方分別調用這個方法。然而需求總是變化的,需要我們一直做修改。
提出一個公共方法,每個接口都來調用這個接口。
將方法注入到接口調用的地方(切點)。
實際上涉及到多個地方具有相同的修改問題都可以通過 AOP 來解決。
AOP術語
AOP 領域中的特性術語:
-
橫切關注點:跨越應用程序多個模塊的方法或功能。與業務邏輯無關,但是需要我們關注的部分,如日志、安全、事務等等....
-
切面(ASPECT):橫切關注點被模塊化的特殊對象(是一個類)
-
通知(Advice):切面必須要完成的工作(是類中的一個方法)
-
目標(Target):被通知對象
-
代理(Proxy):向目標對象應用通知之后創建的對象
-
切入點(PointCut):切面通知執行的“地點”
-
連接點(JointPoint):與切入點匹配的執行點
-
織入(Weaving):將 aspect 和其他對象連接起來, 並創建 adviced object 的過程
AOP的實現
- 通過 Spring API 實現
- 通過自定義類來實現
- 使用注解實現
使用注解實現
編寫一個注解實現的增強類:
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法執行前---------");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法執行后---------");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("環繞前");
System.out.println("簽名:"+jp.getSignature());
//執行目標方法proceed
Object proceed = jp.proceed();
System.out.println("環繞后");
System.out.println(proceed);
}
}
在Spring配置文件中,注冊bean,並增加支持注解的配置:
<!--第三種方式:注解實現-->
<bean id="annotationPointcut" class="com.ldc.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>