spring in action 4th --- quick start
讀spring in action.
- 環境搭建
- quick-start依賴注入
- 面向切面
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.