1. 程式人生 > 其它 >spring in action 4th --- quick start

spring in action 4th --- quick start

讀spring in action. 

  1. 環境搭建
  2. quick-start依賴注入
  3. 面向切面

1.環境搭建

  • jdk1.8
  • gradle 2.12
  • Intelij idea 2016.2.1

1.1建立一個gradle專案

在idea中,new -> project -> gradle 建立一個空專案。建立成功後修改build.gradle :

group 'com.test'
version '1.0-SNAPSHOT'

apply plugin: 'java'
apply plugin: 'war'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    
}

根目錄下建立.gitignore:

# Created by .ignore support plugin (hsz.mobi)
.idea/
.gradle/
build/
out/
*/build/

1.2 quick start

spring的核心是依賴注入,那麼簡單的做一個入門測試。

在專案名上右鍵,new->module->gradle->建立一個java專案quick-start. 修改生產的build.gradle:

group 'com.test'
version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'

    compile 'org.springframework:spring-context:4.3.2.RELEASE'
}

這裡參考:http://projects.spring.io/spring-framework/#quick-start 的案例.

在quick-start module下建立一個package src/main/java,在java資料夾上右鍵,Mark Directory as -> Sources Root.

這時候idea的專案配置還沒有重新整理,需要手動點選一下重新整理:

這時候,idea就可以resolve quick-start這個專案以及他的dependency了。

新增spring-context會新增其他依賴:

dependencies {
    compile 'org.springframework:spring-context:4.3.2.RELEASE'
}

1.2.1 Hello World

我們來建立列印訊息的元件。MessagePrinter列印一個MessageService的例項的資訊。:

建立介面com.test.hello.MessageService:

package com.test.hello;

/**
 * Created by rmiao on 8/15/2016.
 */
public interface MessageService {
    String getMessage();
}

建立元件com.test.hello.MessagePrinter:

package com.test.hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Created by rmiao on 8/15/2016.
 */
@Component
public class MessagePrinter {

    final private MessageService service;

    @Autowired
    public MessagePrinter(MessageService service){
        this.service = service;
    }

    public void printMessage(){
        System.out.println(this.service.getMessage());
    }
}

@Component宣告MessagePrinter是一個bean,由spring容器來管理。

@Autowired 這裡是構造器注入,會根據構造器引數的型別和引數名來將spring容器中的bean注入構造器。

針對MessagePrinter的注入引數,我們需要一個MessageService的實現:

MessageService mockMessageService(){
        return () -> "Hello World!";
}

下面開始啟動spring容器來測試這個列印訊息元件:

建立com.test.hello.Application:

package com.test.hello;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * Created by rmiao on 8/15/2016.
 */
@Configuration
@ComponentScan
public class Application {

    @Bean
    MessageService mockMessageService(){
        return () -> "Hello World!";
    }

    public static void main(String[] args){
        ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        MessagePrinter printer = context.getBean(MessagePrinter.class);
        printer.printMessage();
    }
}

@Configuration來宣告Application是一個配置類,相當於xml配置檔案。這裡只配置了一個bean mockMessageService.

@Bean 用來宣告一個bean並交由spring容器管理。相當於xml配置檔案中<bean>. 這種方式表示宣告一個MessageService的類的bean,bean id為mockMessageService。

@ComponentScan來宣告spring容器掃描範圍,這種方式表示掃描Application所在包以及子包下的所有類,然後將識別到的bean放到spring容器中。

AnnotationConfigApplicationContext用來建立spring容器。getBean來獲取容器中的bean。

最終,列印Hello World! 

1.2.2 Aop面向切面

spring的另一個強大特性是面向切面程式設計。可以在任意方法的呼叫前後進行一些操作。比如記錄日誌:

新增aop依賴:

dependencies {

    compile group: 'org.springframework', name: 'spring-aop', version: '4.3.2.RELEASE'
    compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.8.9'

}

新增logback日誌元件依賴:

dependencies {

    compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.21'
    compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.7'
    compile group: 'ch.qos.logback', name: 'logback-core', version: '1.1.7'
    compile group: 'org.codehaus.groovy', name: 'groovy', version: '2.4.7'

}

在src/main/resources下建立logback.groovy:

import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy
import ch.qos.logback.core.rolling.RollingFileAppender
import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy

import static ch.qos.logback.classic.Level.DEBUG
import static ch.qos.logback.classic.Level.INFO

appender("STDOUT", ConsoleAppender) {
    encoder(PatternLayoutEncoder) {
        pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5}  - %msg%n"
    }
}
appender("FILE", RollingFileAppender){
    file = "quick-start/log/project.log"
    encoder(PatternLayoutEncoder) {
        pattern = "%d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
    }
    rollingPolicy(FixedWindowRollingPolicy) {
        fileNamePattern = "quick-start/log/project.%i.log.zip"
        minIndex = 1
        maxIndex = 10
    }
    triggeringPolicy(SizeBasedTriggeringPolicy) {
        maxFileSize = "2MB"
    }
}

// specify  level
logger("com.test.hello", DEBUG)
//By default, the level of the root level is set to DEBUG
root(DEBUG, ["STDOUT"])

下面開始面相切面程式設計。

我們想要在訊息列印元件的前後做一些工作,但又不想要修改列印元件的內容。那麼可以使用@Aspect:

建立:com.test.hello.Monitor.java:

package com.test.hello;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * Created by rmiao on 8/15/2016.
 */
@Aspect
@Component
public class Monitor {

    private final Logger logger = LoggerFactory.getLogger(Monitor.class);

    @Pointcut("execution(* com.test.hello.MessagePrinter.printMessage())")
    public void  message(){}

    @Before(value = "message()")
    public void pre(){
        logger.info("before print.");
    }

    @After(value = "message()")
    public void after(){
        logger.info("after print.");
    }


}

@Aspect表示這是一個aop切面。等價於xml配置中的<aop>

@Pointcut表示切面的匹配方式

@Before表示切面呼叫前執行

@After表示切面呼叫後執行。

要使上述的配置生效,還需開啟切面,在配置類中宣告@EnableAspectJAutoProxy:

package com.test.hello;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

/**
 * Created by rmiao on 8/15/2016.
 */
@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class Application {

    @Bean
    MessageService mockMessageService(){
        return () -> "Hello World!";
    }

    public static void main(String[] args){
        ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        MessagePrinter printer = context.getBean(MessagePrinter.class);
        printer.printMessage();
    }
}

執行:

八月 15, 2016 9:13:45 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
資訊: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@31cefde0: startup date [Mon Aug 15 21:13:45 CST 2016]; root of context hierarchy
21:13:49.278 [main] INFO  c.t.h.Monitor  - before print.
Hello World!
21:13:49.306 [main] INFO  c.t.h.Monitor  - after print.