1 / 47

Spring 简入简出

Spring 简入简出. 引子 : 在没有 Spring 的日子里. EJB 的例子. EJB 容器架构 : 容器提供服务 组件提供业务逻辑. 口号 : 应用开发者只需 关注业务逻辑. 引子 : 在没有 Spring 的日子里. 写一个 EJB 组件真的只需要关注业务逻辑吗 ?. 一个最基本的 SLSB. 在没有 Spring 的日子里. 淘宝系统早期的各种 Factory. 在没有 Spring 的日子里. 淘宝系统早期的各种 Factory. BO 、 VOF 的构造方式类似. <ao-factories>

floria
Download Presentation

Spring 简入简出

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Spring简入简出

  2. 引子:在没有Spring的日子里 • EJB的例子 • EJB容器架构: • 容器提供服务 • 组件提供业务逻辑 口号: 应用开发者只需 关注业务逻辑

  3. 引子:在没有Spring的日子里 • 写一个EJB组件真的只需要关注业务逻辑吗? 一个最基本的SLSB

  4. 在没有Spring的日子里 • 淘宝系统早期的各种Factory

  5. 在没有Spring的日子里 • 淘宝系统早期的各种Factory BO、VOF 的构造方式类似 <ao-factories> <ao-factory name="XXXAO" class="com....XXXAO" /> <ao-factory name="YYYAO" class="com....YYYAO"> <property name="pName" value="pValue"/> </ao-factory> </ao-factories>

  6. Spring的理念:一个目标,三个原则 • 目标 • 简化J2EE应用开发 • 原则 • 易事简为 • 难事善为 • 重用轮子 易事简为 难事善为 重用轮子 简

  7. Spring的方式:一个中心,三个基础 • 中心 • POJO编程模型 • 基础 • 反向控制 • 面向切面 • 服务抽象 反向控制 (IoC) 面向切面 (AOP) 服务抽象 (Service Abstraction) POJO

  8. Spring的言行一致性 • 目标 • 简化J2EE应用开发 • 原则 • 易事简为 • 难事善为 • 重用轮子 • 中心 • POJO编程模型 • 基础 • 反向控制 • 面向切面 • 服务抽象

  9. POJO编程模型 • 通过POJI松散耦合的POJO • 对象合作:IoC将POJO根据依赖关系组装成一个对象网络 • 对象配置:IoC为POJO提供了一致、灵活的配置机制 • 公共服务:AOP以声明式非侵入的方式将企业服务应用于POJO之上

  10. 应用架构

  11. Spring框架布局 消除 重复代码 基于POJO 简单开发 支持企业服务

  12. Spring运行时环境

  13. 全景透视

  14. Inverse of Control:反向控制 • 好莱坞原则Don’t call me, I’ll call you. • 反向控制原则由框架调用应用代码、控制全局流程;应用代码不调用框架。反向控制是一种原则 • 反向控制原则的普遍性EJB、Servlet、Webx Pipeline、业务应用框架

  15. 反向控制实例:Alipay交易框架

  16. 反向控制实例: Alipay交易框架 • 由容器,而不是组件控制全局规则 • 容器 -> 交易核心框架 • 组件 -> 交易Action • 全局规则 -> action清单和序列、事务边界、并发控制等等

  17. 反向控制实例: Alipay交易框架

  18. Dependency Injection:依赖注入 • 依赖注入是Spring运用反向控制原则解决配置管理和对象关系管理的手段。 • 依赖注入的优势: • 代码简化 • 配置方式统一 • 不依赖特定框架或对象查找API • 自文档化,显式表达依赖关系

  19. DI的类型:设值注入 • 设值注入(setter injection) public interface HollywoodService { public void callMe(); } public class HollywoodServiceImpl implements HollywoodService { private hollywoodManager; public void setHollywoodService (HollywoodManager hollywoodManager) { this. hollywoodManager = hollywoodManager; } public void callMe() { System.out.println(“Don’t call me, I’ll call you!”);} } <beans> <bean id=“hollywoodService” class=“HollywoodServiceImpl”> <property name=“hollywoodManager”> <ref bean=“hollywoodManager”/> </property> </bean> </beans>

  20. DI的类型:构造器注入 • 构造器注入(constructor injection) public interface HollywoodService { public void callMe(); } public class HollywoodServiceImpl implements HollywoodService { private hollywoodManager; public HollywoodServiceImpl (HollywoodManager hollywoodManager) { this. hollywoodManager = hollywoodManager; } public void callMe() { System.out.println(“Don’t call me, I’ll call you!”);} } <beans> <bean id=“hollywoodService” class=“HollywoodServiceImpl”> <construtor-arg> <ref bean=“hollywoodManager”/> </ construtor-arg> </bean> </beans>

  21. DI的类型:方法注入 • 方法注入(method injection) public interface HollywoodService { public void callMe(); } public abstract class HollywoodServiceImpl implements HollywoodService { protected abstract HollywoodManager getHollywoodManager(); public void callMe() { System.out.println(“Don’t call me, I’ll call you!”); getHollywoodManager().notify(); } }

  22. DI的类型:方法注入(cont.) <beans> <bean id=“hollywoodService” class=“HollywoodServiceImpl”> <lookup-method name=“getHollywoodManager” bean=“hollywoodManager”/> </bean> <bean id=“hollywoodManager” singleton=“false” class=“HollywoodManagerImpl”/> </beans> • 方法注入(cont.) • 容器在运行时动态生成方法的实现 • 实现的方式是通过容器对象查找 • 典型应用场景是将一个非单例的bean注入给一个单例的bean,实现每次引用时可以使用一个新的实例,满足线程安全性要求。

  23. DI实例:FactoryBean • FactoryBean是一个特别的接口,当它的实现类作为bean定义时,它代表的不是该类的实例,而是由它创建的对象。 • FactoryBean实例: • JNDIObjectFactoryBean: 查找JNDI获取对象;应用与JNDI API解耦。 <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>ZFBDataSource</value> </property> </bean>

  24. DI实例:FactoryBean(cont.) • PropertyPathFactoryBean: 获取指定bean的属性值 <bean id=“person" class=“…“/> <bean id=“theCity” class=“org.springframework.beans.factory.config.PropertyPathFactoryBean ”> <property name=“targetObject"><ref local=“person”/></property> <property name=“propertyPath"><value>address.city</value></property> </bean> • MethodInvokingFactoryBean: 调用指定bean的方法,获取返回值

  25. DI应用:基于DB的密钥管理器 • 场景: 应用中的加解密操作过程中需要使用密钥,出于安全起见,密钥不应该出现在配置文件或源代码中。在没有专用硬件支持的情况下,一个可行的选择是将密钥保存在DB中,并在系统启动时将密钥注入到加解密操作对象中,如何实现?

  26. DI应用:基于DB的密钥管理器(cont.) • public interface KeyManager { • public String getKeyByName(String keyName); • } • public class KeyManagerImpl { • private KeyDAO keyDAO; • private Map keyMap; • public void init() { • keyMap = keyDAO.findAll(); • } • public String getKeyByName(String keyName) { • return (String) keyMap.get(keyName) • }; • }

  27. DI应用:基于DB的密钥管理器(cont.) • public interface CryptoService { • public String encrypt(String clearText); • } • public class CryptoServiceImpl { • private String key; • private Encrypter encrypter; • public String encrypt(String clearText) { • encrypter.encrypt(key, clearText); • } • public void setKey(String key) { • this.key = key; • } • }

  28. DI应用:基于DB的密钥管理器(cont.) • <bean id="keyManager" class="KeyManagerImpl“ init-method=“init”> • <property name="keyDAO"><ref bean="keyDAO"/></property> • </bean> • <bean id="cryptoService" class=cryptoServiceImpl"> • <property name="key"> • <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> • <property name="targetObject"><value>keyManager</value></property> • <property name="targetMethod"><value>getKeyByName</value></property> • <property name="arguments"> • <list><value>cryptoKey</value></list> • </property> • </bean> • </property> • </bean>

  29. AOP:面向切面编程 • 理解AOP: 交叉关注点 交叉关注点 横切业务领域 与架构分层

  30. AOP:面向切面编程 • 理解AOP: 关注点分解

  31. AOP核心概念 • 切面(aspect)需要实现的交叉功能逻辑。 • 通知?(advice)切面的实现。 • 连接点(jointpoint)应用执行中需要插入切面的点。 • 切入点(pointcut)一组连接点的集合,切面将应用于这组连接点。

  32. AOP核心概念

  33. AOP核心概念 • 引入(introduction)为现存的类引入新的方法或属性。 • 目标对象(target)被通知的对象。 • 代理(proxy)将通知应用于目标对象之后得到的对象。 • 织入(weaving)将通知应用于目标对象的过程。

  34. Spring的AOP支持 • Spring基于代理实现对AOP的支持 • 通过J2SE dynamic proxies,可以代理任意Java 接口。 • 通过CGLIB字节码生成,可以代理Java类。 • Spring的代理机制可以支持由Spring容器创建的bean,无法支持应用中自行new出来的bean。

  35. Spring AOP应用基本步骤

  36. 创建AOP通知

  37. 创建AOP通知示例 • 环绕通知示例 public interface MethodInterceptor extends Interceptor { Object invoke(MethodInvocation invocation) throws Throwable; } public class PerformanceMonitorInterceptor implements MethodInterceptor { private int threshold = 1; .. public Object invoke(MethodInvocation invocation) throws Throwable { long startTime = System.currentTimeMillis(); try { return invocation.proceed(); } finally { long elapseTime = System.currentTimeMillis() - startTime; if (elapseTime > threshold) { logger.info("执行时间超过阈值,实际执行时间为" + elapseTime + "毫秒。"); } } } }

  38. 定义切入点 • Spring提供的静态切入点 • NameMatchMethodPointcutAdvisor: 匹配调用方法的名字 • RegexpMethodPointcutAdvisor: 使用正则表达式匹配调用的类名与方法 <bean id="samplePointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="mappedName"> <value>order*</value> </property> <property name="advice"> <ref bean="sampleAdvice"/> </property> </bean>

  39. 用ProxyFactoryBean织入通知 <bean id="tradeDealer" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>com.beyond.biz.tradecore.TradeDealer</value> </property> <property name="interceptorNames"> <list> <value>tradeDealerPointcutAdvisor</value> </list> </property> <property name="target"><ref bean="tradeDealerTarget"/></property> </bean>

  40. 自动创建代理 • BeanNameAutoProxyCreator为符合相同命名规则的Bean应用一个或一组切面。 • DefaultAdvisorAutoProxyCreator实现了BeanPostProcessor接口。当ApplicationContext读入所有Bean的配置信息后,DefaultAdvisorAutoProxyCreator将扫描上下文,寻找所有的Advisor。它将这些Advisor应用到所有符合Advisor切入点的Bean中。

  41. 自动创建代理示例 <bean id="daoAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list><value>daoPerformanceMonitorInterceptor</value></list> </property> <property name="beanNames"> <value>*DAO</value> </property> </bean>

  42. AOP应用示例:将消息发送统一移到事务外 • 应用场景: 在对象B中,发送邮件(通过异步消息实现)被明智地放在事务外,避免出现事务回滚(相当于业务操作未执行)而邮件发送出去的情况。但对象A的doA()方法在事务中调用对象B的doB()方法,并且假设事务传播属性为PROPAGATION_REQUIRED,造成发送邮件操作实际包含在事务中了,于是当doA()方法的事务回滚时,邮件已经发送出去,给用户带来困扰。

  43. AOP应用示例:将消息发送统一移到事务外(cont.) • 需求:在不改变业务代码的前提下,确保系统中所有的异步消息都移到事务提交成功之后执行 • 这个需求(异步消息需要在事务提交之后再发送)是一个交叉关注点,横切所有的消息发送操作,因此,适于用AOP来实现。

  44. AOP应用示例:将消息发送统一移到事务外(cont.) • 第1步,创建Advice,拦截消息发送操作 public class AfterCommitCommandInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { if (StringUtil.equals(invocation.getMethod().getName(), "execute")) { // 只对execute方法进行拦截 if (TransactionSynchronizationManager.isActualTransactionActive()) { // 由于当前处于活动事务中,因此向事务同步管理器注册同步对象,在事务提交后再执行真正的命令发送。 TransactionSynchronizationManager.registerSynchronization(new MethodInvocationTransactionSynchronization(invocation)); return new ResultSupport(true, ResultCode.SUCCESS); } else { return invocation.proceed(); } } else { return invocation.proceed(); } } }

  45. AOP应用示例:将消息发送统一移到事务外(cont.) • 辅助类:MethodInvocationTransactionSynchronization的实现 public class MethodInvocationTransactionSynchronization implements TransactionSynchronization { private MethodInvocation methodInvocation; public void afterCompletion(int status) { if (status == STATUS_COMMITTED) { try { Object result = methodInvocation.proceed(); } catch (Exception e) { } } } }

  46. AOP应用示例:将消息发送统一移到事务外(cont.) • 第2步,配置Spring自动创建代理,应用Advice <bean id="afterCommitCommandInterceptor" class="com.iwallet.biz.common.aop.AfterCommitCommandInterceptor"/> <bean id="afterCommitCommandAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list><value>afterCommitCommandInterceptor</value></list> </property> <property name="beanNames"> <!-- 这些都是发送异步消息的CommandDispatcher Bean --> <value>messageDispatcher,bankQueryDispatcher,externalNotifyDispatcher,eventMessageDispatcher,gotoneDispatcher</value> </property> </bean>

  47. 讨论与交流

More Related