和咱們常據說的另外一個概念IOC(控制反轉)其實歸根結底實現的功能是相同的,只是一樣的功能站在不一樣的角度來闡述罷了。咱們須要知道的是,什麼叫依賴注入,爲何要依賴注入。搞清這兩點,我想對Spring的學習在思想上就算是上道了。php
在沒用使用Spring的時候——也就是沒有依賴注入的時候,java應用程序的類與類之間要實現相互的功能協做是比較費勁的,某個類(A)要實現它的功能若是須要依賴另外一個類(B)的協做的話,就須要在A類中主動建立出B類的對象,才能使用B類的方法完成功能(這裏看官就不要去糾結靜態方法之類的狀況了)。這等因而A類須要負責B類對象整個生命週期的管理。在極度簡單的狀況下,在一個類中new出另外一個類的對象彷佛並無什麼問題,可是複雜的應用程序類與類的協做關係每每是多邊的,咱們並不知道一個類功能的實現會依賴多少個另類對象來協做,因此在類中自行建立對象而且管理對象的整個生命週期,會形成代碼的高度耦合以及不可想象的複雜度。那麼,試想,若是咱們能將對象的生命週期交給第三方組件來管理,當某個類須要另外的對象時第三方組件就直接建立出來交給它,這樣,類就能夠只專一於本身功能的實現,而不用去管理其餘類對象的生命週期,這樣類的功能就單純了不少。java
是的,你必定已經明白了,Spring(容器)就是這個第三方組件。咱們只須要告訴Spring(容器)有哪些對象須要管理就好了,不用去關心Spring框架是如何建立對象的。這樣,當某個類A須要類B對象時,若是類B已經聲明交給了Sping容器管理,那麼在程序運行到類A須要類B時,Spring容器就經過依賴注入的方式,將類B對象注入到類A中協助完成業務功能。經過第三方組件的依賴注入,對象無需再自行的建立和管理類與類之間的依賴關係了。對象的建立依賴注入的方式也有多種,譬如接口注入,構造方法注入,setter方法注入等等。說到這裏,你對依賴注入應該有比較直白的認知了。至於爲何要依賴注入,上文已經說得很明白了,就是爲了減小代碼中組件之間的耦合度,咱們仍是先經過簡單示例來直觀感覺下依賴注入比本身管理對象的好處吧——spring
public class Man implements Human {
private QQCar car;
public Man() {
this.car = new QQCar();
}
@Override
public void xiabibi() {
}
public void driveCar(){
car.drive();
}
}
複製代碼
接口Car暫有兩個實現:奔馳車和QQ車,在以上Man類和QQCar類高度耦合的代碼中,老司機經過構造器只建立了QQ車對象,因此只能開QQ車,那麼老司機想開奔馳怎麼辦呢,你讓他從新建立奔馳車的對象嗎?這樣高度耦合的代碼彷佛是毫無辦法的,那麼,咱們經過注入對象的方式對上述代碼作一番改進:數據庫
public class Man implements Human {
private Car car;
public Man(Car car) {
this.car = car;
}
@Override
public void xiabibi() {
}
public void driveCar() {
car.drive();
}
}
複製代碼
以上代碼根據多態特性,經過構造器接口注入的方式屏蔽掉了具體的對象實現,這樣,老司機就能想開什麼車就開什麼車了。這就是依賴注入帶來的好處。 express
控制反轉顯然是一個抽象的概念,咱們舉一個鮮明的例子來講明。在現實生活中,人們要用到同樣東西的時候,第一反應就是去找到這件東西,好比想喝新鮮橙汁,在沒有飲品店的日子裏,最直觀的作法就是:買果汁機、買橙子,而後準備開水。值得注意的是:這些都是你本身「主動」創造的過程,也就是說一杯橙汁須要你本身創造。編程
然而到了今時今日,因爲飲品店的盛行,當咱們想喝橙汁時,第一想法就轉換成了找到飲品店的聯繫方式,經過電話等渠道描述你的須要、地址、聯繫方式等,下訂單等待,過一下子就會有人送來橙汁了。app
請注意你並無「主動」去創造橙汁,橙汁是由飲品店創造的,而不是你,然而也徹底達到了你的要求,甚至比你創造的要好上那麼一些。框架
這就是一種控制反轉的理念,上述的例子已經很好的說明了問題,咱們再來描述一下控制反轉的概念:控制反轉是一種經過描述(在 Java 中能夠是 XML 或者註解)並經過第三方(Spring)去產生或獲取特定對象的方式。ide
主動建立的模式中,責任歸於開發者,而在被動的模式下,責任歸於 IoC 容器,基於這樣的被動形式,咱們就說對象被控制反轉了。(也能夠說是反轉了控制)性能
package pojo;
public class Source {
private String fruit;
private String sugar;
private String size;
}
複製代碼
package pojo;
public class JuiceMaker {
// 惟一關聯了一個 Source 對象
private Source source = null;
public String makeJuice(){
String juice = "xxx用戶點了一杯" + source.getFruit() + source.getSugar() + source.getSize();
return juice;
}
}
複製代碼
<?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 name="source" class="pojo.Source">
<property name="fruit" value="橙子"/>
<property name="sugar" value="多糖"/>
<property name="size" value="超大杯"/>
</bean>
<bean name="juickMaker" class="pojo.JuiceMaker">
<property name="source" ref="source" />
</bean>
</beans>
複製代碼
package test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.JuiceMaker;
import pojo.Source;
public class TestSpring {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"applicationContext.xml"}
);
Source source = (Source) context.getBean("source");
System.out.println(source.getFruit());
System.out.println(source.getSugar());
System.out.println(source.getSize());
JuiceMaker juiceMaker = (JuiceMaker) context.getBean("juickMaker");
System.out.println(juiceMaker.makeJuice());
}
}
複製代碼
總結: IoC 和 DI 實際上是同一個概念的不一樣角度描述,DI 相對 IoC 而言,明確描述了「被注入對象依賴 IoC 容器配置依賴對象」
若是說 IoC 是 Spring 的核心,那麼面向切面編程就是 Spring 最爲重要的功能之一了,在數據庫事務中切面編程被普遍使用。
首先,在面向切面編程的思想裏面,把功能分爲核心業務功能,和周邊功能。
周邊功能在 Spring 的面向切面編程AOP思想裏,即被定義爲切面
在面向切面編程AOP的思想裏面,核心業務功能和切面功能分別獨立進行開發,而後把切面功能和核心業務功能 "編織" 在一塊兒,這就叫AOP
AOP可以將那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任(例如事務處理、日誌管理、權限控制等)封裝起來,便於減小系統的重複代碼,下降模塊間的耦合度,並有利於將來的可拓展性和可維護性。
package service;
public class ProductService {
public void doSomeService(){
System.out.println("doSomeService");
}
}
複製代碼
<bean name="productService" class="service.ProductService" />
複製代碼
package aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start log:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("end log:" + joinPoint.getSignature().getName());
return object;
}
}
複製代碼
<?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" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean name="productService" class="service.ProductService" />
<bean id="loggerAspect" class="aspect.LoggerAspect"/>
<!-- 配置AOP -->
<aop:config>
<!-- where:在哪些地方(包.類.方法)作增長 -->
<aop:pointcut id="loggerCutpoint" expression="execution(* service.ProductService.*(..)) "/>
<!-- what:作什麼加強 -->
<aop:aspect id="logAspect" ref="loggerAspect">
<!-- when:在什麼時機(方法前/後/先後) -->
<aop:around pointcut-ref="loggerCutpoint" method="log"/>
</aop:aspect>
</aop:config>
</beans>
複製代碼