Spring的核心思想,總結得非常好!


作者:Java程序媛環環
https://blog.csdn.net/Lubanjava/article/details/100084602

依賴注入是面型接口編程的一種體現,是Spring的核心思想。事實上依賴注入並不是什么高深的技術, 只是被Sping這么以包裝就顯得有些神秘。

class Main {
    interface Language {
        void print(String s);
    }

    static class Java implements Language{
        @Override
        public void print(String x) {
            System.out.println("System.out.print(\""+ x +"\")");
        }
    }

    static class Coder {
        private Language lang = new Java();

        public void helloWorld() {
            lang.print("hello world");
        }
    }

    public static void main(String[] args) {
        Coder coder = new Coder();
        coder.helloWorld();
    }
}

如上代碼清單所示,Coder使用Java語言打印helloworld字符串, 在這里它不但依賴Language接口, 還依賴Java類,這使得它和Java類耦合在一起。要消除這種依賴或者說解耦很容易。

interface Language {
  void print(String s);
}

static class Java implements Language{
  @Override
  public void print(String x) {
    System.out.println("System.out.print(\\""\+ x +"\\")");
  }
}

static class Coder {
  private Language lang;

  public void setLang(Language lang) {
    this.lang = lang;
  }

  public void helloWorld() {
    lang.print("hello world");
  }
}

public static void main(String\[\] args) {
  Coder coder = new Coder();
  Language java = new Java();
  coder.setLang(java);
  coder.helloWorld();
}

我們給Coder類增加了設置具體語言的方法,使得Coder類只依賴Language接口而不依賴具體的語言實現,換言之,Coder類和具體的語言解耦了,此時我們可以輕而易舉的使用其它語言代替Java,比如說使用C#。

static class CSharp implements Language{
    @Override
    public void print(String x) {
        System.out.println("Console.Write(\\""\+ x +"\\")");
    }
}

public static void main(String\[\] args) {
    Coder coder = new Coder();
    Language csharp = new CSharp();
    coder.setLang(csharp);
    coder.helloWorld();
}

關注微信公眾號:Java技術棧,在后台回復:spring,可以獲取我整理的 N 篇最新 Spring 教程,都是干貨。

這種在外部設置某個對象所依賴的具體對象的技巧就是依賴注入,這很很令人以外,一種最常見不過的編碼技巧居然還有如此高大山的名稱。

對於Coder類來說,確定使用何種語言原本實在編譯器期確定的,使用依賴注入后,使用何種語言便延時至運行期。

Spring框架的核心思想便是基於此,不過它的實現更進一步,它把創建各個對象設置依賴關系的過程動態化和通用化了。在我們的代碼清單中,創建對象和設置依賴關系的main方法只適用與當前的情況,而Spring的IOC容器能適用與任何情況

通常,Spring的依賴關系由XML表示,IOC容器解析XML完成對象的創建和依賴注入。

我們將之前的代碼用Spring框架來實現:

interface Language {
    void print(String s);
}
class Java implements Language{
    @Override
    public void print(String x) {
        System.out.println("System.out.print(\""+ x +"\")");
    }
}
class CSharp implements Language{
    @Override
    public void print(String x) {
        System.out.println("Console.Write(\""+ x +"\")");
    }
}
class Coder {
    private Language lang;

    public void setLang(Language lang) {
        this.lang = lang;
    }

    public Language getLang() {
        return lang;
    }

    public void helloWorld() {
        lang.print("hello world");
    }
}

依賴關系將由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-3.0.xsd">

    <bean id="java" class="Java">
    </bean>

    <bean id="csharp" class="CSharp">
    </bean>

    <bean id="coder" class="Coder">
        <property name="lang" ref="csharp"></property>
    </bean>
</beans>

創建Coder對象的代碼變為

public static void main(String[] args) {
    ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");
    Coder coder = (Coder) context.getBean("coder");
    coder.helloWorld();
}

具體的對象創建和依賴關系的設置將由IOC根據XML配置來完成,Spring使得依賴注入機制自動化,但是依賴注入的本質卻沒有變花。2019 最新 Spring 系列教程,都在這了,這篇推薦大家看下。

面向切面編程能實現不改變原有代碼的前提下動態的對功能進行增強, 比如說在一個方法執行前或執行后做某些事情如記錄日志、計算運行時間等等。

Spring中完美集成Aspectj,因此可以很方便的進行面向切面編程。

Spring Aspectj有幾個注解用以實現常用的面向切面編程功能

@Aspect
public class Logger {
    @Before("execution(* controller.Default.*(..))")
    public void before(JoinPoint join){}

    @After("execution(* controller.Default.*(..))")
    public void after(){}

    @AfterReturning("execution(* controller.Default.*(..))")
    public void afterReturning() {}

    @AfterThrowing("execution(* controller.Default.*(..))")
    public void afterThrowing(){}

    @Around("execution(* controller.Default.*(..))")
    public void around(ProceedingJoinPoint jp) {}
}

如上代碼所示, 此類對controller.Default類下的所有方法進行增強。

@Before注解

@Before注解修飾的方法會在被增強的方法執行前被執行

@After注解

@After注解修飾的方法會在被增強的方法執行后被執行

@AfterReturning注解

@AfterReturning注解修飾的方法會在被增強的方法執行后被執行,但前提是被修飾的方法順利執行結束,假如方法中途拋出異常,那么AfterReturning注解修飾的方法將不會被執行,而After注解修飾的方法是無論如何都會被執行。

@AfterThrowing注解

@AfterThrowing注解修飾的方法會在被增強的方法執行出錯拋出異常的情況下被執行。

@Around注解

@Around注解是@Before注解和@After注解的綜合,它可以在被增強的方法的前后同時進行增強

@Around("execution(* controller.Default.*(..))")
public void around(ProceedingJoinPoint jp) {
    try {
        System.out.println("before");
        jp.proceed();
        System.out.println("after");
    } catch (Throwable e) {
        System.out.println(e.getMessage());
    }
}

使用此注解,被增強的方法需要手動編碼調用

jp.proceed();

如果在增強代碼中不寫這一句,那么被增強的方法將不會運行。

此外, 還有一個重要的注解 @Pointcut

@Pointcut注解

此注解可以用來提煉切入點

@Aspect
public class Logger {
    @Pointcut( value = "execution(* controller.Default.*(..))")
    public void pointcut() {}

    @Before("pointcut()")
    public void before(JoinPoint join){}

    @After("pointcut()")
    public void after(){}

    @AfterReturning("pointcut()")
    public void afterReturning() {}

    @AfterThrowing("pointcut()")
    public void afterThrowing(){}

    @Around("pointcut()")
    public void around(ProceedingJoinPoint jp) {}
}

@Before、@After等注解可以應用此注解聲明的切入點,從而減少代碼的重復。

推薦去我的博客閱讀更多:

1.Java JVM、集合、多線程、新特性系列教程

2.Spring MVC、Spring Boot、Spring Cloud 系列教程

3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

4.Java、后端、架構、阿里巴巴等大廠最新面試題

覺得不錯,別忘了點贊+轉發哦!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM