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原型等
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 引入是一個意思。
![](http://static.javashuo.com/static/loading.gif)
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 }