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 @Bean10 public Quest quest() {11 return new SlayDragonQuest(System.out);12 }13 14 @Bean15 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的一生
测试一下:
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
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/