一句話歸納Spring,Spring是一個開源的、輕量的控制反轉(IOC)和面向切面編程(AOP)的框架。html
SpringMVC是在Spring基礎之上結合了MVC三層架構的框架,使用DispatchServlet和視圖解析器作到了更方便的視圖跳轉和控制器調度處理,主要負責處理WEB應用開發。SpringMVC是Spring的一個子模塊。java
SpringBoot則使用了約定大於配置的理念,簡化了Spring配置,專一於微服務的開發。spring
SpringCloud專一於全局微服務的整合、管理。express
IOC:控制反轉,是一種設計思想。即將對象建立的控制權轉移給了Spring容器。編程
假設咱們建立了類A,類A中有個成員變量類B。緩存
使用傳統方式,A對B產生了依賴,也就是A和B之間存在一種耦合關係(假設B的實現有了改動,咱們可能還須要改動A的源碼),而經過IOC的思想,這種依賴關係就被容器取代了,全部對象的建立依賴於容器,在啓動的時候,Spring會讀取配置文件,並將建立的對象先注入容器,以後咱們想要使用直接從容器中取就能夠。架構
DI:依賴注入,能夠理解爲是Spring實現IOC的具體方式。框架
class UserService { private UserDao dao; public void setUserDao(UserDao dao) { this.userDao = dao; } } class UserDao { private String name; public void setName(String name) { this.name = name; } }
<bean id="dao" class="com.dong.dao.UserDao"> <!--使用name定位構造函數--> <constructor-arg name="name" value="dongjh"></constructor-arg> </bean> <bean id="service" class="com.dong.service.UserService"> <!--使用type定位構造函數--> <constructor-arg type="com.dong.dao.UserDao" ref="dao"></constructor-arg> </bean>
注:ide
<bean id="dao" class="com.dong.service.UserDao"> <!--基本類型使用value注入屬性--> <property name="name" value="dongjh"></property> </bean> <bean id="service" class="com.dong.service.UserService"> <!--引用類型使用ref屬性--> <property name="userDao" ref="dao"></property> </bean>
注:函數
setXXX
方法,XXX是property標籤中的name,假設上面的代碼的setName
方法改爲了setName1
,則第一個bean的property需這樣寫:<property name="name1" value="dongjh"></property>
自動裝配即Spring在上下文中自動尋找,自動給bean裝配屬性。
bean的自動裝配主要有三種策略:
byname
:把與某bean(A)屬性具備相同名字的其餘bean(B)自動裝配到該bean(A)的屬性中;byType
:把與某bean(A)屬性具備相同類型的其餘bean(B)自動裝配到該bean(A)的屬性中;constructor
:把與某bean(A)的構造器入參具備相同類型的其餘bean(B)自動裝配到該bean(A)的屬性中;<!--因爲該bean的id爲userDao,因此會直接自動裝配下面service的userDao屬性中--> <bean id="userDao" class="com.dong.service.UserDao"> <property name="name" value="dongjh"></property> </bean> <!--該類有setUserDao方法,且設置了屬性自動裝配byName--> <bean id="service" class="com.dong.service.UserService" autowired="byName"> </bean>
<!--該bean的類型爲com.dong.service.UserDao,因此會直接自動裝配下面service的userDao屬性中--> <bean id="userDao111" class="com.dong.service.UserDao"> <property name="name" value="dongjh"></property> </bean> <!--該類一個com.dong.service.UserDao類型的屬性,且設置了屬性自動裝配byType--> <bean id="service" class="com.dong.service.UserService" autowired="byType"> </bean>
JDK1.5開始支持註解,而Spring是2.5開始支持。
使用Spring註解配置須要先導入約束: context名稱空間和註解掃描。
<?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"> <!--注:只會尋找在同一個應用上下文中定義的註解, 好比將這個聲明放置到DispatcherServlet的配置上下文中, 它就只會檢查controllers的上下文,而不會檢查services的上下文, 詳情見https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-annotation-config--> <context:annotation-config/> <!--指定註解掃描返回--> <context:component-scan base-package="com.dong.dao"></context:component-scan> </beans>
以後在須要自動裝配的屬性或set方法上使用@AutoWired註解,就能夠實現自動裝配。
//詳細的可修飾範圍 @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
注:@Autowired會先使用byType,再按byName的順序自動裝配。
@Autowired有一個經常使用屬性:required,默認值爲true,這個屬性表示修飾的成員變量是否必定須要裝配一個bean:
當有多個bean知足自動裝配條件時,可使用這個指定裝配的bean,通常配合@Autowired使用。
@Qualifier有個屬性value,給這個value設置想要裝配的bean的id便可。
修飾類,表示將該類的bean對象注入到Spring容器中。
@Component有個屬性value,表示注入時設置的id。
如:
//等價於<bean id="user" class="User"> @Component(value="user") public class User {}
@Component有一些衍生註解,如Web開發會按照MVC架構分層,根據不一樣的功能層,衍生出了一些註解:
這四個註解功能一致,都表示將某類的bean對象注入到Spring容器中。
給屬性注入值,主要用於給成員變量注入值,簡單的能夠注入基本類型的值,複雜時能夠注入一些操做系統屬性或其餘bean的屬性。
用於設置bean的做用域,先介紹最多見的:
xml功能更增強大,方便管理維護。註解適用於簡單的屬性注入。
Spring 3.0
以後開始支持了一種更優的配置方式:基於Java類的配置方式。經過增長@Configuration註解代表這是一個配置類,其底層爲@Component(即該類的bean對象也會被Spring容器接管)。
@Configuration結合@Bean註解能夠實現XML配置實現注入的功能,效果與
<beans> <bean>...</bean> <bean>...</bean> </beans>
相似,在使用@Bean註解時,表示將該方法返回的對象加載進Spring容器,在使用@Bean修飾方法時須要注意:
以建立UserService和UserDao爲例:
@Configuration public class UserConfiguration { @Bean public UserService userService() { return new UserService(); } @Bean public UserDao userDao() { return new UserDao(); } }
當Spring掃描該類時,會自動將UserConfiguration、UserService、UserDao的bean注入到Spring容器中進行託管。
在軟件開發中,咱們須要編寫許多的業務代碼,但還有不少代碼是業務無關的,如
爲了實現業務代碼和非業務代碼的分離,Spring利用代理模式抽出了非業務代碼,造成了AOP思想。
AOP全稱Aspect Oriented Programming,意爲面向切面編程,假設業務代碼自己是一條縱向的邏輯流,咱們在其中找幾個點(切點,Pointcut),插入非業務代碼,就像是一個個切面(Aspect),這就是一個簡單的AOP例子。
切面和切點很容易被混淆,嚴格來講,切點是切面的一部分信息,切面主要包含兩部分信息:
而在具體的實現中,Spring爲切面還加了一個信息:在切點的哪一個階段執行?由此衍生出有:
關於AOP在Spring的實現有三種方式:
Spring提供了諸如MethodBeforeAdvice、AfterAdvice、AfterReturningAdvice等原生接口,咱們能夠經過實現這些接口構建切面,如
@Component public class Log implements MethodBeforeAdvice { /** * @param method 要執行的目標對象方法 * @param objects 參數 * @param o 目標對象 * @throws Throwable */ public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println(o.getClass().getName() + "-" + method.getName() + "將要執行"); } }
該Log類實現了MethodBeforeAdvice,成爲了一個在方法執行前插入的切面,其次,咱們須要在XML中進行配置,設置切點並創建其和切面的鏈接:
<aop:config> <!--切入點:execution表達式,execution(要執行的方法!)--> <aop:pointcut id="pointcut" expression="execution(* com.dong.service.UserServiceImpl.*(..))"/> <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor> </aop:config>
execution表示在方法執行時觸發;*表示方法返回值能夠是任意類型,com.dong.service.UserServiceImpl.*使用全限定類名和方法名指定要添加前置通知的方法,使用*表示對com.dong.service.UserServiceImpl類下的全部方法都執行切入;(..)表示方法的參數列表,使用(..)表示方法的入參能夠是任意類型。
須要注意,Log必須是一個被Spring容器管理的bean對象,不然Spring將沒法找到該切面的bean,所以使用@Component註解修飾(也可使用XML配置等方式注入)。
自定義切面不須要實現Spring的原生接口,首先須要定義一個切面類,並將加載給Spring容器進行託管。
@Component(value="diy") public class DiyPointCut { public void before() { System.out.println("方法執行前"); } public void after() { System.out.println("方法執行後"); } }
與3.2類似,該方式須要經過XML配置設置切點以及其和切面的鏈接。
<aop:config> <!--自定義切面,ref:要引用的bean--> <aop:aspect ref="diy"> <aop:pointcut id="pointcut" expression="execution(* com.dong.service.UserServiceImpl.*(..))"/> <!--指定advice和切點的關係--> <aop:before method="before" pointcut-ref="pointcut"></aop:before> <aop:after method="after" pointcut-ref="pointcut"></aop:after> </aop:aspect> </aop:config>
首先,使用註解有兩種方式:
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" 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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--啓用註解--> <context:annotation-config/>、 <!--註解包掃描--> <context:component-scan base-package="com.dong.dao"></context:component-scan> <context:component-scan base-package="com.dong.log"></context:component-scan> <!--啓用aop註解--> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
使用@EnableAspectJAutoProxy
註解須要被切的類
@Component(value = "userService") @EnableAspectJAutoProxy public class UserServiceImpl implements UserService {}
其次,使用註解時,須要注意兩部分:
下面介紹一下註解的使用方式。
只要對一個類使用@Aspect註解修飾,就代表這是一個切面。能夠對其中的方法使用
註解指定切入時機,切入點經過execution表達式指定,舉例以下:
@Aspect @Component public class CustomPointCut { @Before("execution(* com.dong.service.UserServiceImpl.*(..))") public void before() { System.out.println("aop:方法發生前"); } }