• 1. Spring介绍Bob
  • 2. 姓名:沈纯波 旺旺交流群:9292937 Email:shencb@hundsun.com
  • 3. Spring是什么?Spring 是一个开源框架,由Rod Johnson创建,他在<<Expert One-on-One: J2EE Design and Development>>这本书中阐述过这个框架。Spring是为简化企业级系统开发而诞生的。使用Spring,你可以用简单的JavaBean来实现那些以前只有EJB才能实现的功能。不光服务端开发能从中受益,任何Java系统开发都能从Spring的简单、可测试和松耦合特征中得到好处。
  • 4. 轻量级——从大小和系统开发上说Spring都算是轻量级的。整个Spring框架可以打成一个2.5M多一点的Jar包。更重要的是,Spring是非侵入式的:基于Spring开发的系统中的对象一般不依赖于Spring的类。 依赖注入——Spring提倡使用依赖注入(DI)来实现松耦合。使用DI,对象是被动接收依赖类而不是自己主动去找。你可以将DI理解为JNDI的反转——对象不是从容器中查找它的依赖类,而是容器在实例化对象的时候主动将它的依赖类注入给它。 面向切面——Spring对面向切面编程提供了强大支持,通过将业务逻辑从系统服务(如监控和事务管理)中分离出来,实现了内聚开发。系统对象只做它们该做的——业务逻辑,它们不负责(或关心)其他系统问题(如日志和事务支持 )。 容器——Spring是一个容器是因为它包含并且管理系统对象的生命周期和配置。你可以通过配置来设定你的Bean是单一实例,还是每次请求产生一个实例,并且设定它们之间的关联关系。Spring有别于传统的重量级EJB容器,这些容器通常很大,很笨重。 框架——Spring实现了使用简单的组件配置组合成一个复杂的系统。在Spring中,系统中的对象是通过XML文件配置组合起来的。并且Spring提供了很多基础功能(事务管理、持久层集成等等),这使开发人员能够专注于开发应用逻辑。
  • 5. (本页无文本内容)
  • 6. DI是什么?依赖注入经常被引用为另外一个名字:控制反转。但是Martin Fowler在2004年初的文章中问到,控制的什么方面被反转了。他总结说是获得依赖对象的方式反转了。根据这个提示,他取了一个更好听的名字 “依赖注入”,这个术语更好的描述了将要发生的事情。 任何重要的系统(几乎任何比HelloWorld.java复杂的系统)都需要至少两个相互合作的类来完成业务逻辑。通常,每个对象都要自己负责得到它的合作(依赖)对象。这样会导致代码耦合度高而且难以测试。 使用DI,对象的依赖都是在对象创建时由负责协调系统中各个对象的外部实体提供的。这就是依赖被注入到对象中。所以,IoC意味着关于对象如何得到它的协作对象的责任反转了。
  • 7. 介绍BeanFactoryBean工厂是工厂模式的一种实现。也就是说,这是一个负责创建和分发Bean的类。但是,与很多工厂模式实现不同的是,它们只是分发一种类型的对象,而Bean工厂是一个通用的工厂,可以创建和分发各种类型的Bean。 但是,除了简单的实例化和分发应用对象以外,Bean工厂还有很多工作需要做。由于Bean工厂知道应用系统中的很多对象,所以它可以在实例化这些对象的时候,创建协作对象间的关联关系。这样就把配置的负担从Bean自身以及Bean的调用者中脱离出来。结果,Bean 工厂分发出来的Bean都已经被配置好了,都得到了它们的关联对象,已经可以被使用了。Bean 工厂还要参与到Bean的生命周期中,调用用户定义的初始化和销毁方法(如果定义了这些方法的话)。
  • 8. ApplicationContextBeanFactory对简单应用来说已经很好了,但是为了获得Spring框架的强大功能,你需要使用Spring的更加高级的容器,应用上下文。 表面上,ApplicationContext和BeanFactory差不多。两者都是载入Bean定义信息,装配Bean,根据需要分发Bean。但是ApplicationContext提供了更多功能: 应用上下文提供了文本信息解析工具,包括对国际化的支持。 应用上下文提供了载入文件资源的通用方法,如载入图片。 应用上下文可以向注册为监听器的Bean发送事件。 由于它提供的附加功能,几乎所有的应用系统都选择ApplicationContext而不是BeanFactory。只有在资源很少的情况下,才会考虑采用BeanFactory,如在移动设备上。
  • 9. 在ApplicationContext的诸多实现中,有三个实现经常用到: ClassPathXmlApplicationContext——从类路径中的XML文件载入上下文定义信息,把上下文定义文件当成类路径资源。 FileSystemXmlApplicationContext——从文件系统中的XML文件载入上下文定义信息 XmlWebApplicationContext——从Web系统中的XML文件载入上下文定义信息。 ApplicationContext context = new FileSystemXmlApplicationContext("c:/foo.xml"); 同样,你可以使用ClassPathXmlApplicationContext从系统的类路径中载入应用上下文。 ApplicationContext context = new ClassPathXmlApplicationContext("foo.xml"); 使用FileSystemXmlApplicationContext和ClassPathXmlApplicationContext的区别是,FileSystemXmlApplicationContext只能在指定的路径中寻找foo.xml文件,而ClassPathXmlApplicationContext可以在整个类路径中寻找foo.xml(包括JAR文件)。 无论哪种实现 ,你都可以像从BeanFactory中获得Bean一样从ApplicationContext中得到Bean,就是使用getBean()方法。这一点都不奇怪,因为ApplicationContext接口扩展自BeanFactory接口。 除了应用上下文提供的附加功能外,应用上下文与Bean工厂的另一个重要区别是关于单实例Bean是如何被载入的。Bean工厂延迟载入所有的Bean,直到getBean()方法被调用时Bean才被创建。应用上下文则聪明一点,它会在上下文启动后预载入所有的单实例Bean。通过预载入单实例Bean,确保当你需要的时候它们已经准备好了,你的应用不需要等待它们被创建。
  • 10. Bean的生命在传统Java应用中,Bean的生命周期非常简单。Java的关键词new用来实例化Bean(或许它是非序列化的),这样就够用了。相反,Bean的生命周期在Spring容器中更加细致。理解Spring Bean的生命周期非常重要,因为你或许要利用Spring提供的机会来定制Bean的创建过程。
  • 11. 练习:创建Bean
  • 12. (本页无文本内容)
  • 13. 生命周期
  • 14. Instantiate实例化Populate properties设置属性值Set bean name如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的IDSet bean factory如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身Postprocess (before Initialization)如果有BeanPostProcessor和Bean关联,那么它们的postProcessBeforeInitialzation()方法将被调用Initialize bean如果这个bean实现了InitializingBean,那么调用afterertiesSet()方法。如果用户已经声明了一个bean的初始化方法,那么将调用这个特殊的初始化方法。Postprocess (after initialization)如果有BeanPostProcessor和Bean关联,那么它们的postProcessAfterInitialization()将被调用Bean is ready to use 到这时候,Bean已经可以被应用系统使用了,并且将被保留在Bean Factory中直到它不再被需要。Destroy bean如果bean实现了DisposableBean,它的destory()方法被调用; 如果这个Bean已经有一个用户声明的destory方法,那么将调用这个特殊的方法。
  • 15. Bean定义
  • 16. 单实例/非单实例 实例化与销毁
  • 17. Set方法注入 构造函数注入
  • 18. 自动装配 byName——试图在容器中寻找和需要自动装配的属性名相同的Bean。 byType——试图在容器中寻找一个与需要自动配置的属性类型相同的Bean。 Constructor——试图在容器中查找与需要自动装配的Bean的构造函数参数一致的一个或多个Bean。 Autodetect——首先尝试使用constructor来自动装配,然后使用byType方式。
  • 19. 特殊BeanBeanPostProcessor 接口 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; Spring框架中的BeanPostProcessor ApplicationContextAwareProcessor DefaultAdvisorAutoProxyCreator
  • 20. 特殊BeanBeanFactoryPostProcessor 接口 void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; 时机 载入所有Bean定义之后,实例化Bean之前(包括BeanPostProcessor) Spring框架中的BeanFactoryPostProcessor PropertyPlaceholderConfigurer
  • 21. 特殊BeanPropertyPlaceholderConfigurer 替换bean定义文件中的占位符
  • 22. 特殊Bean属性编辑器 PropertyEditor String getAsText(); void setAsText(String text) throws java.lang.IllegalArgumentException; 添加自己的PropertyEditor
  • 23. AOP切面有助于模块化交叉业务。简而言之,一个交叉业务可以被描述成一个作用在一个多个点的功能。例如,安全是一个交叉业务,它关系到系统中的多个应用到安全规则的方法。
  • 24. AOP术语通知(Advice):通知同时定义了切面是什么和在什么时候。除了描述切面的要执行的工作,通知还描述了什么时候来执行这个工作。它应该在调用的方法之前应用吗?还是在方法调用之后?又或是在方法调用前后都用呢?还可能是只在一个方法抛出异常时才用? 连接点(Joinpoint):系统可能有无数的机会来应用通知。这些机会就可以认为是连接点。连接点是应用程序执行过程中插入切面的地点。这个地点可以是方法调用,异常抛出,或者甚至是要修改的字段。切面代码在这些地方插入到你的应用流程中,添加新的行为。 切入点(Pointcut):切入点定义了通知应该应用在哪些连接点。通常通过指定类名和方法名,或者匹配类名和方法名式样的正则表达式来指定切入点。一些AOP框架允许动态创建切入点,在运行时根据条件决定是否应用切面,如方法参数值。 切面(Aspect):切面是通知和切入点的融合。把他们放在一起,通知和切入点定义了关于切面的一切——它是什么,在哪里和什么时候去做。 织入(Weaving):织入是将切面应用到目标对象从而创建一个新的代理对象的过程。切面在指定接入点被织入到目标对象中。织入发生在目标对象生命周期的多个点上:  编译期——切面在目标对象编译时织入。这需要一个特殊的编译器。  类装载期——切面在目标对象被载入到JVM中时织入。这需要一个特殊的类载入器,它在类载入到应用系统之前增强目标对象字节码。  运行期——切面在应用系统运行时织入。通常,AOP容器将在织入切面的时候动态生成委托目标对象的代理对象。
  • 25. 通知Before Advice 在目标对象方法调用前使用的通知 After Advice 在目标对象方法调用完成后使用的通知 Around Advice 在目标对象方法调用前后使用的通知 Throws Advice 发生异常时使用的通知 引入通知 一种特殊通知,为目标对象添加新方法
  • 26. Before Advice
  • 27. After Advice
  • 28. 切入点静态切入点 NameMathMethodPointcut RegexpMethodPointcut 动态切入点 CountrolFlowPointcut 根据线程调用堆栈的信息来匹配方法。也就是说,它可以配置成,只有当指定方法或类能在当前线程执行堆栈中找到时,返回true。
  • 29. ProxyFactoryBean
  • 30. Spring AOP实现BeanNameAutoProxyCreator
  • 31. DefaultAdvisorAutoProxyCreator
  • 32. 在Spring中,通过把切面包在代理类中的方式在运行时把切面织入到被管理的Spring类中 代理Bean只有在第一次被应用系统需要的时候才被创建。如果你使用的是ApplicationContext,代理对象在BeanFactory载入所有Bean的时候被创建。因为Spring在运行期创建代理,所以使用Spring AOP不需要特殊编译器。 Spring有两种代理创建方式。如果目标对象实现了一个(或多个)接口暴露的方法,Spring将使用JDK的java.lang.reflect.Proxy类创建代理。这个类让Spring动态产生一个新的类,它实现了所需的接口,织入了通知,并且代理对目标对象的所有请求。 如果目标对象没有实现任何接口,Spring使用CGLIB库生成目标对象的子类。在创建这个子类的时候,Spring将通知织入,并且将对目标对象的调用委托给这个子类。
  • 33. 事务管理 传统上,J2EE开发者有两个事务管理的选择: 全局 或 本地 事务。全局事务由应用服务器管理,使用JTA。局部事务是和资源相关的,比如一个和JDBC连接关联的事务。这个选择有深刻的含义。例如,全局事务可以用于多个事务性的资源(典型例子是关系数据库和消息队列)。使用局部事务,应用服务器不需要参与事务管理,并且不能帮助确保跨越多个资源(需要指出的是多数应用使用单一事务性的资源)的事务的正确性。 全局事务.  全局事务有一个重大的缺陷,代码需要使用JTA。此外,JTA的UserTransaction通常需要从JNDI获得,这意味着我们为了JTA,需要 同时 使用JNDI 和 JTA。显然全部使用全局事务限制了应用代码的重用性,因为JTA通常只在应用服务器的环境中才能使用。 本地事务. 本地事务容易使用,但也有明显的缺点:它们不能用于多个事务性资源。例如,使用JDBC连接事务管理的代码不能用于全局的JTA事务中。另一个缺点是局部事务趋向于入侵式的编程模型。 Spring解决了这些问题。它使应用开发者能够使用在 任何环境 下使用 一致 的编程模型。你可以只写一次你的代码,这在不同环境下的不同事务管理策略中很有益处。
  • 34. 事务A (Atomicity, 原子性) C (Consistency, 一致性) I (Isolation, 隔离性) D (Durability, 持久性)
  • 35. 原来的JDBC方式
  • 36. Spring中的JDBC编码方式
  • 37. 配置DataSource
  • 38. Spring事务管理器
  • 39. JDBC事务管理DataSourceTransactionManager
  • 40. 编码式事务
  • 41. 声明式事务TransactionProxyFactoryBean
  • 42. Spring远程服务WebService(Xfire) RMI(Remote Method Invocation) Hessian and Burlap HttpInvoker
  • 43. 核心理念 远程服务透明化 技术术语 将本地服务暴露成远程服务 透明访问远程服务
  • 44. Xfire远程调用配置Server端配置 45. Xfire远程调用配置Client端配置 com.hundsun.poc.remoting.service.echo.EchoService http://localhost:8080/hgs- remoting/services/xfire/EchoService?wsdl
  • 46. Spring单元测试AbstractDependencyInjectionSpringContextTests AbstractTransactionalSpringContextTests AbstractTransactionalDataSourceSpringContextTests
  • 47. Spring单元测试AbstractDependencyInjectionSpringContextTests 通过getConfigLocations() 方法指明配置文件 通过setter方法或基类的applicationContext获得依赖的Bean 通过setAutowireMode(int autowireMode)方法改变自动输入方式(默认是byType) AbstractTransactionalSpringContextTests 增加了PlatformTransactionManager成员变量 调用setComplete()方法,指明需要提交事务 调用endTransaction()方法,指明结束事务 onSetUpBeforeTransaction() onSetUpInTransaction() onTearDownInTransaction() onTearDownAfterTransaction() AbstractTransactionalDataSourceSpringContextTests 增加了JdbcTemplate成员变量 需要在配置文件中定义DataSource