Spring 實戰4學習筆記(轉)

http://blog.csdn.net/21aspnet/article/details/51386557html

1.IOC裝配Beanjava

參考【spring實戰4 2.2】,做者提倡無XML配置化。web

1.1接口只有一個現實類spring

能夠自動裝配編程

1 package demo;
2 
3 public interface CompactDisc {
4     void play(); 
5 }

實現類api

 1 package demo;
 2 
 3 import org.springframework.stereotype.Component;
 4 
 5 @Component 
6
public class SgtPeppers implements CompactDisc{ 7 private String title = "Sgt. Pepper's Lonely Hearts Club Band"; 8 private String artist = "http://blog.csdn.net/unix21"; 9 10 public void play() { 11 System.out.println("【很是醒目SgtPeppers 】>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist); 12 } 13 }

 配置類多線程

 1 package demo;
 2 
 3 import org.springframework.context.annotation.ComponentScan;
 4 import org.springframework.context.annotation.Configuration;
 5 
 6 @Configuration  
 7 @ComponentScan  
 8 public class CDPlayerConfig {
 9 
10 }

單元測試類mvc

 1 package demo;
 2 import org.junit.Test;
 3 import org.junit.runner.RunWith;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.beans.factory.annotation.Qualifier;
 6 import org.springframework.test.context.ContextConfiguration;
 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
 8   
 9 @RunWith(SpringJUnit4ClassRunner.class)  
10 @ContextConfiguration(classes = CDPlayerConfig.class)  
11 public class CDPlayerTest {  
12     @Autowired  
13     @Qualifier("spn")
14     private CompactDisc cd;  
15    
16     @Test  
17     public void play() {  
18         cd.play();  
19     }  
20 } 

測試結果app


1.2 接口有多個實現類ide

【參考 Spring實戰4 3.3】
故意再寫一個實現類

 1 package demo;
 2 
 3 import org.springframework.context.annotation.Primary;
 4 import org.springframework.stereotype.Component;
 5 
 6 
 7 @Component 
 8 public class SgtPeppersNew implements CompactDisc{
 9     private String title = "Sgt. Pepper's Lonely Hearts Club Band";  
10     private String artist = "http://blog.csdn.net/unix21";  
11       
12     public void play() {  
13         System.out.println("【很是醒目SgtPeppersNew 】>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);  
14     }  
15 }

此時有兩個實現類,若是這時執行單元測試類的時候,測試類不知道注入(DI)那個實現類,因此會報錯。

兩種解決方案:1,加@Primary 首選標識的bean  2, 使用@Qualifier註解@Qualifier("SgtPeppersNew"), 改變@Component("SgtPeppersNew")   或者@Qualifier 註解中用實現類,但id是小寫@Qualifier("sgtPeppersNew"),不須要改變@Component

 1 package demo;
 2 
 3 import org.springframework.stereotype.Component;
 4 
 5 
 6 @Component
 7 public class SgtPeppersNew implements CompactDisc{
 8     private String title = "Sgt. Pepper's Lonely Hearts Club Band";  
 9     private String artist = "http://blog.csdn.net/unix21";  
10       
11     public void play() {  
12         System.out.println("【很是醒目SgtPeppersNew 】>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);  
13     }  
14 }
 1 package demo;
 2 import org.junit.Test;
 3 import org.junit.runner.RunWith;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.beans.factory.annotation.Qualifier;
 6 import org.springframework.test.context.ContextConfiguration;
 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
 8   
 9 @RunWith(SpringJUnit4ClassRunner.class)  
10 @ContextConfiguration(classes = CDPlayerConfig.class)  
11 public class CDPlayerTest {  
12     @Autowired  
13     @Qualifier("sgtPeppersNew")
14     private CompactDisc cd;  
15    
16     @Test  
17     public void play() {  
18         cd.play();  
19     }  
20 } 

打印結果

1.3 爲組件掃描的bean命名  

【參考 Spring實戰4  2.2.2】

1 import org.springframework.stereotype.Component;  
2   
3 @Component("spn")  
4 public class SgtPeppersNew implements CompactDisc { 
1     @Autowired  
2     @Qualifier("spn")   
3     private CompactDisc cd;  

也可使用@Named效果是同樣的,這是java依賴注入規範

1 import javax.inject.Named;  
2   
3 @Named("spn")  
4 public class SgtPeppersNew implements CompactDisc {  

1.4 設定組件掃描的指定包

【參考 Spring實戰4  2.2.3】

若是@ComponentScan默認不設置只掃描配置類所在的包做爲基礎包

@Configuration  
@ComponentScan("blog.csdn.net.unix21")  
public class CDPlayerConfigTest 

設置@ComponentScan的value屬性就能夠指明包名稱。

 

 

若是想更清晰的代表設置的是基礎包
@ComponentScan(basePackages="指定包")

 

指定多個

@ComponentScan(basePackages={"指定包1","指定包2"})

 

也能夠將其指定爲包中所包含的類或者接口

@ComponentScan(basePackages={"XXX.class","XX.class"})

 

1.5 自動裝配

【參考 Spring實戰4  2.2.4】

聲明自動裝配須要@Autowired註解

1.5.1 在構造方法上使用自動裝配

 1 package demo;
 2 import org.junit.Test;
 3 import org.junit.runner.RunWith;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.beans.factory.annotation.Qualifier;
 6 import org.springframework.test.context.ContextConfiguration;
 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
 8   
 9 @RunWith(SpringJUnit4ClassRunner.class)  
10 @ContextConfiguration(classes = CDPlayerConfigTest.class)  
11 public class CDPlayerFunTest {  
12     private CompactDisc cd;  
13     @Autowired  
14     @Qualifier("spn") 
15     public void CDPlayer(CompactDisc cd) {  
16         this.cd = cd;  
17     }  
18    
19     @Test  
20     public void play() {  
21         cd.play();  
22         System.out.println("【佔位符】CDPlayerFunTest");  
23     }  
24 } 

另外一種寫法

 1 @Component  
 2 public class CDPlayer implements MediaPlayer {  
 3   private CompactDisc cd;  
 4   
 5   @Autowired  
 6   public CDPlayer(@Qualifier("spn")CompactDisc cd) {  
 7     this.cd = cd;  
 8   }  
 9   
10   public void play() {  
11     cd.play();  
12   }  
13   
14 }  

1.5.2 在屬性Setter方法上使用自動裝配

 1 @Component  
 2 public class CDPlayer implements MediaPlayer {  
 3   private CompactDisc cd;  
 4     
 5   @Autowired  
 6   @Qualifier("spn")  
 7   public void setCompactDisc(CompactDisc cd) {  
 8     this.cd = cd;  
 9   }  
10   
11   public void play() {  
12     cd.play();  
13   }  
14 }  

避免異常聲明  @Autowired(required = false),若是沒有匹配的bean,Spring會讓這個bean處於未裝配轉態,可是須要謹慎對待這個設置,代碼須要作null檢查。

@Autowired是Spring特有的註解,能夠替換爲@Inject,@Inject來源自Jave依賴注入規範。

1.6 建立自定義的限定符

【參考 Spring實戰4  3.3.2】

@Component  
@Qualifier("cold")  
public class IceCream implements CompactDisc {  
  
    private String title = "Sgt. Pepper's Lonely Hearts Club Band";  
    private String artist = "The Beatles";  
  
    public void play() {  
        System.out.println("【很是醒目 IceCream】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);  
    }  
}  
 1 @RunWith(SpringJUnit4ClassRunner.class)  
 2 @ContextConfiguration(classes=CDPlayerConfigTest.class)  
 3 public class CDPlayerLogTest {  
 4   
 5   @Autowired  
 6   private MediaPlayer player;  
 7     
 8   @Autowired  
 9   @Qualifier("sp")  
10   private CompactDisc cd;  
11     
12   @Autowired  
13   @Qualifier("cold")  
14   private CompactDisc cd2;  
15     
16   @Test  
17   public void cdShouldNotBeNull() {  
18     assertNotNull(cd);  
19   }  
20   
21   @Test  
22   public void play() {  
23     player.play();  
24     cd.play();  
25     cd2.play();  
26   }  
27 }  

好處:這樣作的好處限定符不耦合類名,因此能夠隨意重構類名。

問題:重複的限定符出如今多個類上這是不容許的,由於Java不容許同一個條目上重複出現相同類型的多個註解

注意:此時我用本地測試時發現  private MediaPlayer player;  這個player 並不能注入到測試類中,須要之後解決。

解決:注意其實CDplayer 也是須要建立的組件類,因此也要加上@Component

 

1.7 使用自定義限定符註解

 

針對上述問題能夠建立自定義的限定符註解。

1 @Retention(RetentionPolicy.RUNTIME) // 註解會在class字節碼文件中存在,在運行時能夠經過反射獲取到    
2 @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定義註解的做用目標**做用範圍字段、枚舉的常量/方法    
3 @Qualifier  
4 public @interface Cold {}  
1 @Retention(RetentionPolicy.RUNTIME) // 註解會在class字節碼文件中存在,在運行時能夠經過反射獲取到    
2 @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定義註解的做用目標**做用範圍字段、枚舉的常量/方法    
3 @Qualifier  
4 public @interface Creamy {}  
1 @Retention(RetentionPolicy.RUNTIME) // 註解會在class字節碼文件中存在,在運行時能夠經過反射獲取到    
2 @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定義註解的做用目標**做用範圍字段、枚舉的常量/方法    
3 @Qualifier  
4 public @interface Fruity {}  
 1 @Component  
 2 @Cold  
 3 @Creamy  
 4 public class IceCream implements CompactDisc {  
 5   
 6     private String title = "Spring 實現 第4版 讀書筆記";  
 7     private String artist = "http://blog.csdn.net/unix21";  
 8   
 9     public void play() {  
10         System.out.println("【很是醒目 IceCream】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);  
11     }  
12 }  
 1 @Component  
 2 @Cold  
 3 @Fruity  
 4 public class Popsicle implements CompactDisc {  
 5   
 6     private String title = "Spring 實現 第4版 讀書筆記";  
 7     private String artist = "http://blog.csdn.net/unix21";  
 8   
 9     public void play() {  
10         System.out.println("【很是醒目 Popsicle】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);  
11     }  
12 }  
 1 @RunWith(SpringJUnit4ClassRunner.class)  
 2 @ContextConfiguration(classes = CDPlayerConfigTest.class)  
 3 public class CDPlayerLogTest {  
 4   
 5     @Autowired  
 6     private MediaPlayer player;  
 7   
 8     @Autowired  
 9     @Qualifier("sp")  
10     private CompactDisc cd;  
11   
12     @Autowired  
13     @Cold  
14     @Creamy  
15     private CompactDisc cd2;  
16   
17     @Autowired  
18     @Cold  
19     @Fruity  
20     private CompactDisc cd3;  
21   
22     @Test  
23     public void cdShouldNotBeNull() {  
24         assertNotNull(cd);  
25     }  
26   
27     @Test  
28     public void play() {  
29         player.play();  
30         cd.play();  
31         cd2.play();  
32         cd3.play();  
33     }  
34 }  

1.8 bean的做用域

Spring定義了多重做用域,singleton單例,prototype原型等

參考:spring中scope做用域

singleton單例:整個應用中,只建立bean的一個實例,默認Spring上下文中全部的bean都是單例。

prototype原型:每次注入或者經過Spring應用上下文獲取的時候,都會建立一個新的bean實例。

 

 1 @Component  
 2 public class Add implements AddI {  
 3     public  int a=0;  
 4      
 5     public  void Add() {  
 6         a++;  
 7     }  
 8       
 9     public  void getA() {  
10         System.out.println("【很是醒目 Add】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>a= " +a+"");  
11     }  
12 }  
1 public interface AddI {  
2 void Add();  
3     void getA();  
4 }  
 1 @Component  
 2 public class CDPlayer implements MediaPlayer {  
 3   
 4     @Autowired  
 5     @Qualifier("sp")  
 6     private CompactDisc cd;  
 7       
 8     @Autowired  
 9     private AddI a;  
10   
11     public void play() {  
12         System.out.println("【很是醒目 CDPlayer】>>>");  
13         cd.play();  
14         a.Add();  
15         a.getA();  
16         a.Add();  
17         a.getA();  
18         System.out.println("【很是醒目 CDPlayer】<<<");  
19     }  
20 }  

測試用例

 1 @RunWith(SpringJUnit4ClassRunner.class)  
 2 @ContextConfiguration(classes = CDPlayerConfigTest.class)  
 3 public class CDPlayerLogTest {  
 4   
 5     @Autowired  
 6     private MediaPlayer player;  
 7   
 8     @Autowired  
 9     @Qualifier("sp")  
10     private CompactDisc cd;  
11   
12     @Autowired  
13     @Cold  
14     @Creamy  
15     private CompactDisc cd2;  
16   
17     @Autowired  
18     @Cold  
19     @Fruity  
20     private CompactDisc cd3;  
21   
22     @Test  
23     public void cdShouldNotBeNull() {  
24         assertNotNull(cd);  
25     }  
26   
27     @Autowired  
28     private AddI a;  
29       
30     @Test  
31     public void play() {  
32         player.play();  
33         cd.play();  
34         cd2.play();  
35         cd3.play();  
36         a.getA();  
37     }  
38 }  

 

再寫一個多線程

 1 public class ClientThread extends Thread {  
 2   
 3     @Autowired  
 4     private AddI a;  
 5   
 6     @Autowired  
 7     public ClientThread(AddI a) {  
 8         this.a = a;  
 9     }  
10   
11     public void run() {  
12         a.Add();  
13         a.getA();  
14     }  
15 }  

調用多線程

 1 @RunWith(SpringJUnit4ClassRunner.class)  
 2 @ContextConfiguration(classes = CDPlayerConfigTest.class)  
 3 public class SpringScopeTest {  
 4   
 5     @Autowired  
 6     private AddI a;  
 7   
 8     @Test  
 9     public void Scope() {  
10         for (int i = 0; i < 10; i++) {  
11             ClientThread t = new ClientThread(a);  
12             t.start();  
13         }  
14     }  
15 }  

此時add實現類以下

@Component
//@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)  
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)  
public class Add implements AddI{
    public  int a=0; 
    public void Add() {
        // TODO Auto-generated method stub
        a++;  
    }

    public void getA() {
        // TODO Auto-generated method stub
        System.out.println("【很是醒目 Add】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>a= " +a+"");  
    }

}

若是使用單例模式則

補充說明:@Repository、@Service、@Controller 和 @Component將類標識爲Bean,都是同樣的,用在不一樣的地方而已。

 

2.AOP切面編程

定義接口

 

1 public interface PerformanceI {  
2     public void perform();  
3 } 

實現類

1 import org.springframework.stereotype.Component;  
2   
3 @Component  
4 public class Performance implements PerformanceI{  
5     public void perform(){  
6     System.out.println("【很是醒目  Performance perform 調用中】 By http://blog.csdn.net/unix21");     
7     }  
8 }  

定義切面

 1 import org.aspectj.lang.annotation.After;  
 2 import org.aspectj.lang.annotation.AfterThrowing;  
 3 import org.aspectj.lang.annotation.Aspect;  
 4 import org.aspectj.lang.annotation.Before;  
 5   
 6 @Aspect  
 7 public class MyAspect {  
 8     @Before("execution(* com.demo.PerformanceI.perform(..))")  
 9     public void before(){  
10     System.out.println("【很是醒目 [方法調用前] 】");  
11     }  
12       
13     @After("execution(* com.demo.PerformanceI.perform(..))")  
14     public void after(){  
15     System.out.println("【很是醒目 [方法調用後] 】");  
16     }  
17       
18     @AfterThrowing("execution(* com.demo.PerformanceI.perform(..))")  
19     public void afterThrowing(){  
20     System.out.println("【很是醒目 [方法異常後] 】");  
21     }  
22 } 

配置文件

 1 import com.demo.*;  
 2 import org.springframework.context.annotation.Bean;  
 3 import org.springframework.context.annotation.ComponentScan;  
 4 import org.springframework.context.annotation.Configuration;  
 5 import org.springframework.context.annotation.EnableAspectJAutoProxy;  
 6   
 7 @Configuration  
 8 @EnableAspectJAutoProxy  
 9 @ComponentScan("com.demo")  
10 public class AppConfig {  
11     @Bean  
12     public MyAspect myAspect() {  
13         return new MyAspect();  
14     }  
15      
16 }  

測試用例

 1 import org.junit.Test;  
 2 import org.junit.runner.RunWith;  
 3 import org.springframework.beans.factory.annotation.Autowired;  
 4 import org.springframework.test.context.ContextConfiguration;  
 5 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
 6   
 7 @RunWith(SpringJUnit4ClassRunner.class)  
 8 @ContextConfiguration(classes = AppConfig.class)  
 9 public class MyTest {  
10   
11     @Autowired  
12     private PerformanceI p1;  
13       
14     @Test  
15     public void play() {  
16         p1.perform();  
17     }  
18 }  

此時在本地運行報錯··········

 後來加入了  aopalliance.jar 包後解決問題 已經寫入到 博客園內 問題3.

實現了方法調用先後的AOP效果。

 

 

這個Spring官方參考作的不錯:http://docs.spring.io/spring/docs/4.2.5.RELEASE/javadoc-api/

 

這裏選不一樣的版本:http://docs.spring.io/spring/docs/

 4.3.2 建立環繞通知

哈哈此小結我的以爲挺有意思因此也就拿上來了。

環繞通知是最爲強大的通知類型。它可以讓你所編寫的邏輯將被通知的目標方法徹底包裝起 來。實際上就像在一個通知方法中同時編寫前置通知和後置通知。

環繞通知,直接上代碼說事情。

 1 package concert;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 import org.aspectj.lang.annotation.Around;
 5 import org.aspectj.lang.annotation.Aspect;
 6 import org.aspectj.lang.annotation.Pointcut;  
 7 @Aspect  
 8 public class MyAspect {
 9     @Pointcut("execution(* concert.PerformanceI.perform(..))")
10     public void perform(){}
11     @Around("perform()")
12     public void watchPerformance(ProceedingJoinPoint jp){  
13         try{
14             System.out.println("【很是醒目 [方法調用前] 】"); 
15             jp.proceed();
16             System.out.println("【很是醒目 [方法調用後] 】");  
17         } catch (Throwable e){
18             System.out.println("【很是醒目 [方法異常後] 】");  
19         }
20     }  
21 }
@Around 是環繞通知的 註釋,ProceedingJoinPoint 做爲參數用來通知「想作的業務邏輯」 我的理解就是切點。
粘貼過來一張原圖,是經過XML配置來實現AOP切面功能,跟上面 經過基於AspectJ註解 @EnableAspectJAutoProxy 引入是一個意思。

 

 

3.Spring MVC

DispatcherServlet是Spring MVC的核心,每當應用接受一個HTTP請求,由DispatcherServlet負責將請求分發給應用的其餘組件。

首選給出一張Spring MVC的組件圖,也是Spring mvc 的流程圖

 


在舊版本中,DispatcherServlet之類的servlet通常在web.xml文件中配置;可是Spring 3.1引入了註解就無需再使用web.xml文件。

 下面配置DispatcherServlet 

 1 import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;  
 2   
 3 public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {  
 4   
 5     @Override  
 6     protected Class<?>[] getRootConfigClasses() {  
 7         return new Class<?>[]{RootConfig.class};  
 8     }  
 9   
10     @Override  
11     protected Class<?>[] getServletConfigClasses() {  
12         return new Class<?>[]{WebConfig.class};  
13     }  
14   
15     @Override  
16     protected String[] getServletMappings() {  
17         return new String[]{"/"};  
18     }  
19   
20 }  
相關文章
相關標籤/搜索