Spring in Action(一) Core Spring:Spring into Action(2)
Spring的核心是dependency injection (DI) and aspect-oriented programming (AOP).
第一章概览一下什么是Spring,以及DI和AOP是怎么解耦(decoupling )应用组件的。
第二章讲模块、bean怎么连接起来,我们会了解spring提供的三种配置方式:自动配置,基于java的配置和用xml配置。【wiring beans,不清楚标准翻译法,暂翻译为连接,装配,反正大概就是这个意思】
第三章延续第二章讲一些高级的技术技巧,包括带有特定条件的配置,自动装配时的歧义处理,域,以及Spring表达式语言。【Spring Expression Language)】
第四章讲Spring的AOP如何解耦全路服务(比如安全控制及审计)【decouple system-wide services (such as security and auditing) 】
1.2 bean容器
基于Spring的应用的对象是通过Spring container 来管理的,包括创建,装配,配置和管理生命周期。
分两大类,Bean factories(接口定义在org.springframework.beans.factory.BeanFactory )是最简单的容器,提供简单的DI支持。Application contexts (接口定义在org.springframework.context.ApplicationContext )提供应用框架服务,比如从properties文件解析文字消息,向相关listeners发布events等。
1.2.1 application context
- AnnotationConfigApplicationContext 从一个或多个基于java的配置类加载一个Spring application context
- AnnotationConfigWebApplicationContext 同上,加载的是Spring web application context
- ClassPathXmlApplicationContext 从一个或多个作为classpath资源的xml文件加载一个content defination
- FileSystemXmlApplicationContext 从一个或多个文件系统中的xml文件加载一个context defination
- XmlWebApplicationContext 从一个web应用中的一个或多个xml文件加载content definations
关于web的以后再说。先看其他三个:
1 public class ApplicationContextTest { 2 public static void main(String[] args) { 3 ApplicationContext context = new FileSystemXmlApplicationContext("D:/test/knight.xml"); 4 Knight knight = context.getBean(Knight.class); 5 System.out.println(knight); 6 knight.embarkOnQuest(); 7 8 context = new ClassPathXmlApplicationContext("META-INF/spring/knight.xml"); 9 knight = context.getBean(Knight.class); 10 System.out.println(knight); 11 knight.embarkOnQuest(); 12 13 context = new AnnotationConfigApplicationContext(KnightConfig.class); 14 knight = context.getBean(Knight.class); 15 knight.embarkOnQuest(); 16 17 } 18 }
你会发现第三个运行时没有切面,因为我们在xml里声明了切面而config里没有,需要做如下修改:
1 @Configuration 2 @EnableAspectJAutoProxy 3 public class KnightConfig { 4 @Bean 5 public Knight knight(){ 6 return new BraveKnight(quest()); 7 } 8 9 @Bean 10 public Quest quest() { 11 return new SlayDragonQuest(System.out); 12 } 13 14 @Bean 15 public Minstrel minstrel(){ 16 return new Minstrel(System.out); 17 } 18 }
1 @Aspect 2 public class Minstrel { 3 private PrintStream printStream; 4 5 public Minstrel(PrintStream printStream) { 6 this.printStream = printStream; 7 } 8 9 @Pointcut("execution(* *.embarkOnQuest(..))") 10 public void performance() { 11 } 12 13 @Before("performance()") 14 public void singBeforeQuest() { 15 printStream.println("Fa la la, the knight is so brave"); 16 } 17 18 @After("performance()") 19 public void singAfterQuest() { 20 printStream.println("Tee he he, the brave knight did embark on a quest"); 21 } 22 }
注意不要丢了注解。注解名可读性都很强,基本能够解释它是做什么的,运行刚才的测试类,发现一切正常。OK。
1.2.2 bean的一生
测试一下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class ANonsense implements Nonsense, BeanNameAware, BeanFactoryAware,ApplicationContextAware ,BeanPostProcessor,InitializingBean,DisposableBean{ 2 private static int i = 0; 3 4 private String property; 5 private String id; 6 private BeanFactory beanFactory; 7 private ApplicationContext applicationContext; 8 9 public void printOrder(String methodName,Object...params) { 10 System.out.println("method " + methodName + " called at the order " + i++); 11 ArrayList<Object> paramList = new ArrayList<>(params.length); 12 Collections.addAll(paramList,params); 13 System.out.println("params :" + paramList); 14 } 15 16 public ANonsense(String property) { 17 this.property = property; 18 printOrder("constructor"); 19 } 20 21 @Override 22 public void setBeanName(String id) { 23 this.id = id; 24 printOrder("setBeanName",id); 25 } 26 27 @Override 28 public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 29 this.beanFactory = beanFactory; 30 printOrder("setBeanFactory",beanFactory); 31 } 32 33 @Override 34 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 35 this.applicationContext = applicationContext; 36 printOrder("setApplicationContext",applicationContext); 37 } 38 39 @Override 40 public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { 41 printOrder("postProcessBeforeInitialization",o,s); 42 return o; 43 } 44 45 @Override 46 public Object postProcessAfterInitialization(Object o, String s) throws BeansException { 47 printOrder("postProcessAfterInitialization",o,s); 48 return o; 49 } 50 51 @Override 52 public void nonsenseMethod() { 53 System.out.println("use the bean"); 54 } 55 56 @Override 57 public void afterPropertiesSet() throws Exception { 58 printOrder("afterPropertiesSet"); 59 } 60 61 public void init(){ 62 printOrder("init"); 63 } 64 65 @Override 66 public void destroy() throws Exception { 67 printOrder("destory"); 68 } 69 }
1 public class NonsenseTest { 2 public static void main(String[] args) { 3 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/nonsense.xml"); 4 Nonsense nonsense = context.getBean(Nonsense.class); 5 nonsense.nonsenseMethod(); 6 7 CompactDisc d = context.getBean(CompactDisc.class); 8 d.play(); 9 context.close(); 10 11 } 12 }
结果可能跟上图有一些出入,具体原因可能要在以后慢慢了解了,目前我们要知道的事是:bean在container中有生命周期,他们的调用是有一定顺序的,在使用时一定要注意这个顺序。
初始化先配属性,然后是名字、工厂、上下文,BeanPostProcessor包了两个,一个是InitializingBean的afterPropertiesSet() ,一个是配置的init方法。这里要特别注意下BeanPostProcessor并没有直接包在init方法两边,而是放了一个afterPropertiesSet() 方法进来,这一点是比较容易让人困惑的,所以要特别注意下。
1.2.3 spring地图
一些网站:
http://projects.spring.io/spring-webflow/
http://docs.spring.io/spring-ws/site/
http://projects.spring.io/spring-security/
http://projects.spring.io/spring-integration/
http://projects.spring.io/spring-batch/
http://projects.spring.io/spring-android/