当前位置: 首页 > news >正文

深圳网站建设哪家比较专业晋中市两学一做网站

深圳网站建设哪家比较专业,晋中市两学一做网站,深圳宝安网站建设报价,中国建设人才专业服务网框架相关1. Spring refresh 流程2. Spring bean 生命周期3. Spring bean 循环依赖解决 set 循环依赖的原理4. Spring 事务失效5. Spring MVC 执行流程6. Spring 注解7. SpringBoot 自动配置原理8. Spring 中的设计模式1. Spring refresh 流程 Spring refresh 概述 refresh 是… 框架相关1. Spring refresh 流程2. Spring bean 生命周期3. Spring bean 循环依赖解决 set 循环依赖的原理4. Spring 事务失效5. Spring MVC 执行流程6. Spring 注解7. SpringBoot 自动配置原理8. Spring 中的设计模式1. Spring refresh 流程 Spring refresh 概述 refresh 是 AbstractApplicationContext 中的一个方法负责初始化 ApplicationContext 容器容器必须调用 refresh 才能正常工作。它的内部主要会调用 12 个方法我们把它们称为 refresh 的 12 个步骤 prepareRefresh obtainFreshBeanFactory prepareBeanFactory postProcessBeanFactory invokeBeanFactoryPostProcessors registerBeanPostProcessors initMessageSource initApplicationEventMulticaster onRefresh registerListeners finishBeanFactoryInitialization finishRefresh 功能分类 1 为准备环境 2 3 4 5 6 为准备 BeanFactory 7 8 9 10 12 为准备 ApplicationContext 11 为初始化 BeanFactory 中非延迟单例 bean 1. prepareRefresh 这一步创建和准备了 Environment 对象它作为 ApplicationContext 的一个成员变量 Environment 对象的作用之一是为后续 Value值注入时提供键值 Environment 分成三个主要部分 systemProperties - 保存 java 环境键值systemEnvironment - 保存系统环境键值自定义 PropertySource - 保存自定义键值例如来自于 *.properties 文件的键值 2. obtainFreshBeanFactory 这一步获取或创建 BeanFactory它也是作为 ApplicationContext 的一个成员变量BeanFactory 的作用是负责 bean 的创建、依赖注入和初始化bean 的各项特征由 BeanDefinition 定义 BeanDefinition 作为 bean 的设计蓝图规定了 bean 的特征如单例多例、依赖关系、初始销毁方法等BeanDefinition 的来源有多种多样可以是通过 xml 获得、配置类获得、组件扫描获得也可以是编程添加 所有的 BeanDefinition 会存入 BeanFactory 中的 beanDefinitionMap 集合 3. prepareBeanFactory 这一步会进一步完善 BeanFactory为它的各项成员变量赋值beanExpressionResolver 用来解析 SpEL常见实现为 StandardBeanExpressionResolverpropertyEditorRegistrars 会注册类型转换器 它在这里使用了 ResourceEditorRegistrar 实现类并应用 ApplicationContext 提供的 Environment 完成 ${ } 解析 registerResolvableDependency 来注册 beanFactory 以及 ApplicationContext让它们也能用于依赖注入beanPostProcessors 是 bean 后处理器集合会工作在 bean 的生命周期各个阶段此处会添加两个 ApplicationContextAwareProcessor 用来解析 Aware 接口ApplicationListenerDetector 用来识别容器中 ApplicationListener 类型的 bean 4. postProcessBeanFactory 这一步是空实现留给子类扩展。 一般 Web 环境的 ApplicationContext 都要利用它注册新的 Scope完善 Web 下的 BeanFactory 这里体现的是模板方法设计模式 5. invokeBeanFactoryPostProcessors 这一步会调用 beanFactory 后处理器beanFactory 后处理器充当 beanFactory 的扩展点可以用来补充或修改 BeanDefinition常见的 beanFactory 后处理器有 ConfigurationClassPostProcessor – 解析 Configuration、Bean、Import、PropertySource 等PropertySourcesPlaceHolderConfigurer – 替换 BeanDefinition 中的 ${ }MapperScannerConfigurer – 补充 Mapper 接口对应的 BeanDefinition 6. registerBeanPostProcessors 这一步是继续从 beanFactory 中找出 bean 后处理器添加至 beanPostProcessors 集合中bean 后处理器充当 bean 的扩展点可以工作在 bean 的实例化、依赖注入、初始化阶段常见的有 AutowiredAnnotationBeanPostProcessor 功能有解析 AutowiredValue 注解CommonAnnotationBeanPostProcessor 功能有解析 ResourcePostConstructPreDestroyAnnotationAwareAspectJAutoProxyCreator 功能有为符合切点的目标 bean 自动创建代理 7. initMessageSource 这一步是为 ApplicationContext 添加 messageSource 成员实现国际化功能去 beanFactory 内找名为 messageSource 的 bean如果没有则提供空的 MessageSource 实现 8. initApplicationContextEventMulticaster 这一步为 ApplicationContext 添加事件广播器成员即 applicationContextEventMulticaster它的作用是发布事件给监听器去 beanFactory 找名为 applicationEventMulticaster 的 bean 作为事件广播器若没有会创建默认的事件广播器之后就可以调用 ApplicationContext.publishEvent(事件对象) 来发布事件 9. onRefresh 这一步是空实现留给子类扩展 SpringBoot 中的子类在这里准备了 WebServer即内嵌 web 容器 体现的是模板方法设计模式 10. registerListeners 这一步会从多种途径找到事件监听器并添加至 applicationEventMulticaster事件监听器顾名思义用来接收事件广播器发布的事件有如下来源 事先编程添加的来自容器中的 bean来自于 EventListener 的解析 要实现事件监听器只需要实现 ApplicationListener 接口重写其中 onApplicationEvent(E e) 方法即可 11. finishBeanFactoryInitialization 这一步会将 beanFactory 的成员补充完毕并初始化所有非延迟单例 beanconversionService 也是一套转换机制作为对 PropertyEditor 的补充embeddedValueResolvers 即内嵌值解析器用来解析 Value 中的 ${ }借用的是 Environment 的功能singletonObjects 即单例池缓存所有单例对象 对象的创建都分三个阶段每一阶段都有不同的 bean 后处理器参与进来扩展功能 12. finishRefresh 这一步会为 ApplicationContext 添加 lifecycleProcessor 成员用来控制容器内需要生命周期管理的 bean如果容器中有名称为 lifecycleProcessor 的 bean 就用它否则创建默认的生命周期管理器准备好生命周期管理器就可以实现 调用 context 的 start即可触发所有实现 LifeCycle 接口 bean 的 start调用 context 的 stop即可触发所有实现 LifeCycle 接口 bean 的 stop 发布 ContextRefreshed 事件整个 refresh 执行完成 2. Spring bean 生命周期 bean 生命周期 概述 bean 的生命周期从调用 beanFactory 的 getBean 开始到这个 bean 被销毁可以总结为以下七个阶段 处理名称检查缓存处理父子容器处理 dependsOn选择 scope 策略创建 bean类型转换处理销毁 bean 注意 划分的阶段和名称并不重要重要的是理解整个过程中做了哪些事情 1. 处理名称检查缓存 这一步会处理别名将别名解析为实际名称对 FactoryBean 也会特殊处理如果以 开头表示要获取 FactoryBean 本身否则表示要获取其产品这里针对单例对象会检查一级、二级、三级缓存 singletonFactories 三级缓存存放单例工厂对象earlySingletonObjects 二级缓存存放单例工厂的产品对象 如果发生循环依赖产品是代理无循环依赖产品是原始对象 singletonObjects 一级缓存存放单例成品对象 2. 处理父子容器 如果当前容器根据名字找不到这个 bean此时若父容器存在则执行父容器的 getBean 流程父子容器的 bean 名称可以重复 3. 处理 dependsOn 如果当前 bean 有通过 dependsOn 指定了非显式依赖的 bean这一步会提前创建这些 dependsOn 的 bean所谓非显式依赖就是指两个 bean 之间不存在直接依赖关系但需要控制它们的创建先后顺序 4. 选择 scope 策略 对于 singleton scope首先到单例池去获取 bean如果有则直接返回没有再进入创建流程对于 prototype scope每次都会进入创建流程对于自定义 scope例如 request首先到 request 域获取 bean如果有则直接返回没有再进入创建流程 5.1 创建 bean - 创建 bean 实例 要点总结有自定义 TargetSource 的情况由 AnnotationAwareAspectJAutoProxyCreator 创建代理返回Supplier 方式创建 bean 实例为 Spring 5.0 新增功能方便编程方式创建 bean 实例FactoryMethod 方式 创建 bean 实例① 分成静态工厂与实例工厂② 工厂方法若有参数需要对工厂方法参数进行解析利用 resolveDependency③ 如果有多个工厂方法候选者还要进一步按权重筛选AutowiredAnnotationBeanPostProcessor① 优先选择带 Autowired 注解的构造② 若有唯一的带参构造也会入选mbd.getPreferredConstructors选择所有公共构造这些构造之间按权重筛选采用默认构造如果上面的后处理器和 BeanDefiniation 都没找到构造采用默认构造即使是私有的 5.2 创建 bean - 依赖注入 要点总结AutowiredAnnotationBeanPostProcessor识别 Autowired 及 Value 标注的成员封装为 InjectionMetadata 进行依赖注入CommonAnnotationBeanPostProcessor识别 Resource 标注的成员封装为 InjectionMetadata 进行依赖注入resolveDependency用来查找要装配的值可以识别① Optional② ObjectFactory 及 ObjectProvider③ Lazy 注解④ Value 注解${ }, #{ }, 类型转换⑤ 集合类型CollectionMap数组等⑥ 泛型和 Qualifier用来区分类型歧义⑦ primary 及名字匹配用来区分类型歧义AUTOWIRE_BY_NAME根据成员名字找 bean 对象修改 mbd 的 propertyValues不会考虑简单类型的成员AUTOWIRE_BY_TYPE根据成员类型执行 resolveDependency 找到依赖注入的值修改 mbd 的 propertyValuesapplyPropertyValues根据 mbd 的 propertyValues 进行依赖注入即xml中 property name ref 5.3 创建 bean - 初始化 要点总结内置 Aware 接口的装配包括 BeanNameAwareBeanFactoryAware 等扩展 Aware 接口的装配由 ApplicationContextAwareProcessor 解析执行时机在 postProcessBeforeInitializationPostConstruct由 CommonAnnotationBeanPostProcessor 解析执行时机在 postProcessBeforeInitializationInitializingBean通过接口回调执行初始化initMethod根据 BeanDefinition 得到的初始化方法执行初始化即 bean init-method 或 Bean(initMethod)创建 aop 代理由 AnnotationAwareAspectJAutoProxyCreator 创建执行时机在 postProcessAfterInitialization 5.4 创建 bean - 注册可销毁 bean 在这一步判断并登记可销毁 bean 判断依据 如果实现了 DisposableBean 或 AutoCloseable 接口则为可销毁 bean如果自定义了 destroyMethod则为可销毁 bean如果采用 Bean 没有指定 destroyMethod则采用自动推断方式获取销毁方法名closeshutdown如果有 PreDestroy 标注的方法 存储位置 singleton scope 的可销毁 bean 会存储于 beanFactory 的成员当中自定义 scope 的可销毁 bean 会存储于对应的域对象当中prototype scope 不会存储需要自己找到此对象销毁 存储时都会封装为 DisposableBeanAdapter 类型对销毁方法的调用进行适配 6. 类型转换处理 如果 getBean 的 requiredType 参数与实际得到的对象类型不同会尝试进行类型转换 7. 销毁 bean 销毁时机 singleton bean 的销毁在 ApplicationContext.close 时此时会找到所有 DisposableBean 的名字逐一销毁自定义 scope bean 的销毁在作用域对象生命周期结束时prototype bean 的销毁可以通过自己手动调用 AutowireCapableBeanFactory.destroyBean 方法执行销毁 同一 bean 中不同形式销毁方法的调用次序 优先后处理器销毁即 PreDestroy其次 DisposableBean 接口销毁最后 destroyMethod 销毁包括自定义名称推断名称AutoCloseable 接口 多选一 3. Spring bean 循环依赖 要求 掌握单例 set 方式循环依赖的原理掌握其它循环依赖的解决方法 循环依赖的产生 首先要明白bean 的创建要遵循一定的步骤必须是创建、注入、初始化三步这些顺序不能乱 set 方法包括成员变量的循环依赖如图所示 可以在【a 创建】和【a set 注入 b】之间加入 b 的整个流程来解决 【b set 注入 a】 时可以成功因为之前 a 的实例已经创建完毕 a 的顺序及 b 的顺序都能得到保障 构造方法的循环依赖如图所示显然无法用前面的方法解决 构造循环依赖的解决 思路1 a 注入 b 的代理对象这样能够保证 a 的流程走通后续需要用到 b 的真实对象时可以通过代理间接访问 思路2 a 注入 b 的工厂对象让 b 的实例创建被推迟这样能够保证 a 的流程先走通后续需要用到 b 的真实对象时再通过 ObjectFactory 工厂间接访问 示例1用 Lazy 为构造方法参数生成代理 public class App60_1 {static class A {private static final Logger log LoggerFactory.getLogger(A);private B b;public A(Lazy B b) {log.debug(A(B b) {}, b.getClass());this.b b;}PostConstructpublic void init() {log.debug(init());}}static class B {private static final Logger log LoggerFactory.getLogger(B);private A a;public B(A a) {log.debug(B({}), a);this.a a;}PostConstructpublic void init() {log.debug(init());}}public static void main(String[] args) {GenericApplicationContext context new GenericApplicationContext();context.registerBean(a, A.class);context.registerBean(b, B.class);AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());context.refresh();System.out.println();} }示例2用 ObjectProvider 延迟依赖对象的创建 public class App60_2 {static class A {private static final Logger log LoggerFactory.getLogger(A);private ObjectProviderB b;public A(ObjectProviderB b) {log.debug(A({}), b);this.b b;}PostConstructpublic void init() {log.debug(init());}}static class B {private static final Logger log LoggerFactory.getLogger(B);private A a;public B(A a) {log.debug(B({}), a);this.a a;}PostConstructpublic void init() {log.debug(init());}}public static void main(String[] args) {GenericApplicationContext context new GenericApplicationContext();context.registerBean(a, A.class);context.registerBean(b, B.class);AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());context.refresh();System.out.println(context.getBean(A.class).b.getObject());System.out.println(context.getBean(B.class));} }示例3用 Scope 产生代理 public class App60_3 {public static void main(String[] args) {GenericApplicationContext context new GenericApplicationContext();ClassPathBeanDefinitionScanner scanner new ClassPathBeanDefinitionScanner(context.getDefaultListableBeanFactory());scanner.scan(com.itheima.app60.sub);context.refresh();System.out.println();} }Component class A {private static final Logger log LoggerFactory.getLogger(A);private B b;public A(B b) {log.debug(A(B b) {}, b.getClass());this.b b;}PostConstructpublic void init() {log.debug(init());} }Scope(proxyMode ScopedProxyMode.TARGET_CLASS) Component class B {private static final Logger log LoggerFactory.getLogger(B);private A a;public B(A a) {log.debug(B({}), a);this.a a;}PostConstructpublic void init() {log.debug(init());} }示例4用 Provider 接口解决原理上与 ObjectProvider 一样Provider 接口是独立的 jar 包需要加入依赖 dependencygroupIdjavax.inject/groupIdartifactIdjavax.inject/artifactIdversion1/version /dependencypublic class App60_4 {static class A {private static final Logger log LoggerFactory.getLogger(A);private ProviderB b;public A(ProviderB b) {log.debug(A({}}), b);this.b b;}PostConstructpublic void init() {log.debug(init());}}static class B {private static final Logger log LoggerFactory.getLogger(B);private A a;public B(A a) {log.debug(B({}}), a);this.a a;}PostConstructpublic void init() {log.debug(init());}}public static void main(String[] args) {GenericApplicationContext context new GenericApplicationContext();context.registerBean(a, A.class);context.registerBean(b, B.class);AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());context.refresh();System.out.println(context.getBean(A.class).b.get());System.out.println(context.getBean(B.class));} }解决 set 循环依赖的原理 一级缓存 作用是保证单例对象仅被创建一次 第一次走 getBean(a) 流程后最后会将成品 a 放入 singletonObjects 一级缓存后续再走 getBean(a) 流程时先从一级缓存中找这时已经有成品 a就无需再次创建 一级缓存与循环依赖 一级缓存无法解决循环依赖问题分析如下 无论是获取 bean a 还是获取 bean b走的方法都是同一个 getBean 方法假设先走 getBean(a)当 a 的实例对象创建接下来执行 a.setB() 时需要走 getBean(b) 流程红色箭头 1当 b 的实例对象创建接下来执行 b.setA() 时又回到了 getBean(a) 的流程红色箭头 2但此时 singletonObjects 一级缓存内没有成品的 a陷入了死循环 二级缓存 解决思路如下 再增加一个 singletonFactories 缓存在依赖注入前即 a.setB() 以及 b.setA() 将 a 及 b 的半成品对象未完成依赖注入和初始化放入此缓存执行依赖注入时先看看 singletonFactories 缓存中是否有半成品的对象如果有拿来注入顺利走完流程 对于上面的图 a new A() 执行之后就会把这个半成品的 a 放入 singletonFactories 缓存即 factories.put(a)接下来执行 a.setB()走入 getBean(b) 流程红色箭头 3这回再执行到 b.setA() 时需要一个 a 对象有没有呢有factories.get() 在 singletonFactories 缓存中就可以找到红色箭头 4 和 5b 的流程能够顺利走完将 b 成品放入 singletonObject 一级缓存返回到 a 的依赖注入流程红色箭头 6 二级缓存与创建代理 二级缓存无法正确处理循环依赖并且包含有代理创建的场景分析如下 spring 默认要求在 a.init 完成之后才能创建代理 pa proxy(a)由于 a 的代理创建时机靠后在执行 factories.put(a) 向 singletonFactories 中放入的还是原始对象接下来箭头 3、4、5 这几步 b 对象拿到和注入的都是原始对象 三级缓存 简单分析的话只需要将代理的创建时机放在依赖注入之前即可但 spring 仍然希望代理的创建时机在 init 之后只有出现循环依赖时才会将代理的创建时机提前。所以解决思路稍显复杂 图中 factories.put(fa) 放入的既不是原始对象也不是代理对象而是工厂对象 fa当检查出发生循环依赖时fa 的产品就是代理 pa没有发生循环依赖fa 的产品是原始对象 a假设出现了循环依赖拿到了 singletonFactories 中的工厂对象通过在依赖注入前获得了 pa红色箭头 5这回 b.setA() 注入的就是代理对象保证了正确性红色箭头 7还需要把 pa 存入新加的 earlySingletonObjects 缓存红色箭头 6a.init 完成后无需二次创建代理从哪儿找到 pa 呢earlySingletonObjects 已经缓存蓝色箭头 9 当成品对象产生放入 singletonObject 后singletonFactories 和 earlySingletonObjects 就中的对象就没有用处清除即可 4. Spring 事务失效 1. 抛出检查异常导致事务不能正确回滚 Service public class Service1 {Autowiredprivate AccountMapper accountMapper;Transactionalpublic void transfer(int from, int to, int amount) throws FileNotFoundException {int fromBalance accountMapper.findBalanceBy(from);if (fromBalance - amount 0) {accountMapper.update(from, -1 * amount);new FileInputStream(aaa);accountMapper.update(to, amount);}} }原因Spring 默认只会回滚非检查异常 解法配置 rollbackFor 属性 Transactional(rollbackFor Exception.class) 2. 业务方法内自己 try-catch 异常导致事务不能正确回滚 Service public class Service2 {Autowiredprivate AccountMapper accountMapper;Transactional(rollbackFor Exception.class)public void transfer(int from, int to, int amount) {try {int fromBalance accountMapper.findBalanceBy(from);if (fromBalance - amount 0) {accountMapper.update(from, -1 * amount);new FileInputStream(aaa);accountMapper.update(to, amount);}} catch (FileNotFoundException e) {e.printStackTrace();}} }原因事务通知只有捉到了目标抛出的异常才能进行后续的回滚处理如果目标自己处理掉异常事务通知无法知悉 解法1异常原样抛出 在 catch 块添加 throw new RuntimeException(e); 解法2手动设置 TransactionStatus.setRollbackOnly() 在 catch 块添加 TransactionInterceptor.currentTransactionStatus().setRollbackOnly(); 3. aop 切面顺序导致导致事务不能正确回滚 Service public class Service3 {Autowiredprivate AccountMapper accountMapper;Transactional(rollbackFor Exception.class)public void transfer(int from, int to, int amount) throws FileNotFoundException {int fromBalance accountMapper.findBalanceBy(from);if (fromBalance - amount 0) {accountMapper.update(from, -1 * amount);new FileInputStream(aaa);accountMapper.update(to, amount);}} }Aspect public class MyAspect {Around(execution(* transfer(..)))public Object around(ProceedingJoinPoint pjp) throws Throwable {LoggerUtils.get().debug(log:{}, pjp.getTarget());try {return pjp.proceed();} catch (Throwable e) {e.printStackTrace();return null;}} }原因事务切面优先级最低但如果自定义的切面优先级和他一样则还是自定义切面在内层这时若自定义切面没有正确抛出异常… 解法1、2同情况2 中的解法:1、2 解法3调整切面顺序在 MyAspect 上添加 Order(Ordered.LOWEST_PRECEDENCE - 1) 不推荐 4. 非 public 方法导致的事务失效 Service public class Service4 {Autowiredprivate AccountMapper accountMapper;Transactionalvoid transfer(int from, int to, int amount) throws FileNotFoundException {int fromBalance accountMapper.findBalanceBy(from);if (fromBalance - amount 0) {accountMapper.update(from, -1 * amount);accountMapper.update(to, amount);}} }原因Spring 为方法创建代理、添加事务通知、前提条件都是该方法是 public 的 解法1改为 public 方法 解法2添加 bean 配置如下不推荐 Bean public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource(false); }5. 父子容器导致的事务失效 package day04.tx.app.service;// ...Service public class Service5 {Autowiredprivate AccountMapper accountMapper;Transactional(rollbackFor Exception.class)public void transfer(int from, int to, int amount) throws FileNotFoundException {int fromBalance accountMapper.findBalanceBy(from);if (fromBalance - amount 0) {accountMapper.update(from, -1 * amount);accountMapper.update(to, amount);}} }控制器类 package day04.tx.app.controller;// ...Controller public class AccountController {Autowiredpublic Service5 service;public void transfer(int from, int to, int amount) throws FileNotFoundException {service.transfer(from, to, amount);} }App 配置类 Configuration ComponentScan(day04.tx.app.service) EnableTransactionManagement // ... public class AppConfig {// ... 有事务相关配置 }Web 配置类 Configuration ComponentScan(day04.tx.app) // ... public class WebConfig {// ... 无事务配置 }现在配置了父子容器WebConfig 对应子容器AppConfig 对应父容器发现事务依然失效 原因子容器扫描范围过大把未加事务配置的 service 扫描进来 解法1各扫描各的不要图简便 解法2不要用父子容器所有 bean 放在同一容器 6. 调用本类方法导致传播行为失效 Service public class Service6 {Transactional(propagation Propagation.REQUIRED, rollbackFor Exception.class)public void foo() throws FileNotFoundException {LoggerUtils.get().debug(foo);bar();}Transactional(propagation Propagation.REQUIRES_NEW, rollbackFor Exception.class)public void bar() throws FileNotFoundException {LoggerUtils.get().debug(bar);} }原因本类方法调用不经过代理因此无法增强 解法1依赖注入自己代理来调用 解法2通过 AopContext 拿到代理对象来调用 解法3通过 CTWLTW 实现功能增强 解法1 Service public class Service6 {Autowiredprivate Service6 proxy; // 本质上是一种循环依赖Transactional(propagation Propagation.REQUIRED, rollbackFor Exception.class)public void foo() throws FileNotFoundException {LoggerUtils.get().debug(foo);System.out.println(proxy.getClass());proxy.bar();}Transactional(propagation Propagation.REQUIRES_NEW, rollbackFor Exception.class)public void bar() throws FileNotFoundException {LoggerUtils.get().debug(bar);} }解法2还需要在 AppConfig 上添加 EnableAspectJAutoProxy(exposeProxy true) Service public class Service6 {Transactional(propagation Propagation.REQUIRED, rollbackFor Exception.class)public void foo() throws FileNotFoundException {LoggerUtils.get().debug(foo);((Service6) AopContext.currentProxy()).bar();}Transactional(propagation Propagation.REQUIRES_NEW, rollbackFor Exception.class)public void bar() throws FileNotFoundException {LoggerUtils.get().debug(bar);} }7. Transactional 没有保证原子行为 Service public class Service7 {private static final Logger logger LoggerFactory.getLogger(Service7.class);Autowiredprivate AccountMapper accountMapper;Transactional(rollbackFor Exception.class)public void transfer(int from, int to, int amount) {int fromBalance accountMapper.findBalanceBy(from);logger.debug(更新前查询余额为: {}, fromBalance);if (fromBalance - amount 0) {accountMapper.update(from, -1 * amount);accountMapper.update(to, amount);}}public int findBalance(int accountNo) {return accountMapper.findBalanceBy(accountNo);} }上面的代码实际上是有 bug 的假设 from 余额为 1000两个线程都来转账 1000可能会出现扣减为负数的情况 原因事务的原子性仅涵盖 insert、update、delete、select … for update 语句select 方法并不阻塞 如上图所示红色线程和蓝色线程的查询都发生在扣减之前都以为自己有足够的余额做扣减 8. Transactional 方法导致的 synchronized 失效 针对上面的问题能否在方法上加 synchronized 锁来解决呢 Service public class Service7 {private static final Logger logger LoggerFactory.getLogger(Service7.class);Autowiredprivate AccountMapper accountMapper;Transactional(rollbackFor Exception.class)public synchronized void transfer(int from, int to, int amount) {int fromBalance accountMapper.findBalanceBy(from);logger.debug(更新前查询余额为: {}, fromBalance);if (fromBalance - amount 0) {accountMapper.update(from, -1 * amount);accountMapper.update(to, amount);}}public int findBalance(int accountNo) {return accountMapper.findBalanceBy(accountNo);} }答案是不行原因如下 synchronized 保证的仅是目标方法的原子性环绕目标方法的还有 commit 等操作它们并未处于 sync 块内可以参考下图发现蓝色线程的查询只要在红色线程提交之前执行那么依然会查询到有 1000 足够余额来转账 解法1synchronized 范围应扩大至代理方法调用 解法2使用 select … for update 替换 select 5. Spring MVC 执行流程 概要 我把整个流程分成三个阶段 准备阶段匹配阶段执行阶段 准备阶段 在 Web 容器第一次用到 DispatcherServlet 的时候会创建其对象并执行 init 方法 init 方法内会创建 Spring Web 容器并调用容器 refresh 方法 refresh 过程中会创建并初始化 SpringMVC 中的重要组件 例如 MultipartResolverHandlerMappingHandlerAdapterHandlerExceptionResolver、ViewResolver 等 容器初始化后会将上一步初始化好的重要组件赋值给 DispatcherServlet 的成员变量留待后用 匹配阶段 用户发送的请求统一到达前端控制器 DispatcherServlet DispatcherServlet 遍历所有 HandlerMapping 找到与路径匹配的处理器 ① HandlerMapping 有多个每个 HandlerMapping 会返回不同的处理器对象谁先匹配返回谁的处理器。其中能识别 RequestMapping 的优先级最高 ② 对应 RequestMapping 的处理器是 HandlerMethod它包含了控制器对象和控制器方法信息 ③ 其中路径与处理器的映射关系在 HandlerMapping 初始化时就会建立好 将 HandlerMethod 连同匹配到的拦截器生成调用链对象 HandlerExecutionChain 返回 遍历HandlerAdapter 处理器适配器找到能处理 HandlerMethod 的适配器对象开始调用 调用阶段 执行拦截器 preHandle 由 HandlerAdapter 调用 HandlerMethod ① 调用前处理不同类型的参数 ② 调用后处理不同类型的返回值 第 2 步没有异常 ① 返回 ModelAndView ② 执行拦截器 postHandle 方法 ③ 解析视图得到 View 对象进行视图渲染 第 2 步有异常进入 HandlerExceptionResolver 异常处理流程 最后都会执行拦截器的 afterCompletion 方法 如果控制器方法标注了 ResponseBody 注解则在第 2 步就会生成 json 结果并标记 ModelAndView 已处理这样就不会执行第 3 步的视图渲染 6. Spring 注解 事务注解 EnableTransactionManagement会额外加载 4 个 bean BeanFactoryTransactionAttributeSourceAdvisor 事务切面类TransactionAttributeSource 用来解析事务属性TransactionInterceptor 事务拦截器TransactionalEventListenerFactory 事务监听器工厂 Transactional 核心 Order 切面 EnableAspectJAutoProxy 会加载 AnnotationAwareAspectJAutoProxyCreator它是一个 bean 后处理器用来创建代理如果没有配置 EnableAspectJAutoProxy又需要用到代理如事务则会使用 InfrastructureAdvisorAutoProxyCreator 这个 bean 后处理器 组件扫描与配置类 Component Controller Service Repository ComponentScan Conditional Configuration 配置类其实相当于一个工厂, 标注 Bean 注解的方法相当于工厂方法Bean 不支持方法重载, 如果有多个重载方法, 仅有一个能入选为工厂方法Configuration 默认会为标注的类生成代理, 其目的是保证 Bean 方法相互调用时, 仍然能保证其单例特性Configuration 中如果含有 BeanFactory 后处理器, 则实例工厂方法会导致 MyConfig 提前创建, 造成其依赖注入失败解决方法是改用静态工厂方法或直接为 Bean 的方法参数依赖注入, 针对 Mapper 扫描可以改用注解方式 Bean Import 四种用法 ① 引入单个 bean ② 引入一个配置类 ③ 通过 Selector 引入多个类 ④ 通过 beanDefinition 注册器 解析规则 同一配置类中, Import 先解析 Bean 后解析同名定义, 默认后面解析的会覆盖前面解析的不允许覆盖的情况下, 如何能够让 MyConfig(主配置类) 的配置优先? (虽然覆盖方式能解决)采用 DeferredImportSelector因为它最后工作, 可以简单认为先解析 Bean, 再 Import Lazy 加在类上表示此类延迟实例化、初始化加在方法参数上此参数会以代理方式注入 PropertySource 依赖注入 AutowiredQualifierValue mvc mapping RequestMapping可以派生多个注解如 GetMapping 等 mvc rest RequestBodyResponseBody组合 Controller RestControllerResponseStatus mvc 统一处理 ControllerAdvice组合 ResponseBody RestControllerAdviceExceptionHandler mvc 参数 PathVariable mvc ajax CrossOrigin boot auto SpringBootApplicationEnableAutoConfigurationSpringBootConfiguration boot condition ConditionalOnClassclasspath 下存在某个 class 时条件才成立ConditionalOnMissingBeanbeanFactory 内不存在某个 bean 时条件才成立ConditionalOnProperty配置文件中存在某个 property键、值时条件才成立 boot properties ConfigurationProperties会将当前 bean 的属性与配置文件中的键值进行绑定EnableConfigurationProperties会添加两个较为重要的 bean ConfigurationPropertiesBindingPostProcessorbean 后处理器在 bean 初始化前调用下面的 binderConfigurationPropertiesBinder真正执行绑定操作 7. SpringBoot 自动配置原理 自动配置原理 SpringBootConfiguration 是一个组合注解由 ComponentScan、EnableAutoConfiguration 和 SpringBootConfiguration 组成 SpringBootConfiguration 与普通 Configuration 相比唯一区别是前者要求整个 app 中只出现一次 ComponentScan excludeFilters - 用来在组件扫描时进行排除也会排除自动配置类 EnableAutoConfiguration 也是一个组合注解由下面注解组成 AutoConfigurationPackage – 用来记住扫描的起始包Import(AutoConfigurationImportSelector.class) 用来加载 META-INF/spring.factories 中的自动配置类 为什么不使用 Import 直接引入自动配置类 有两个原因 让主配置类和自动配置类变成了强耦合主配置类不应该知道有哪些从属配置直接用 Import(自动配置类.class)引入的配置解析优先级较高自动配置类的解析应该在主配置没提供时作为默认配置 因此采用了 Import(AutoConfigurationImportSelector.class) 由 AutoConfigurationImportSelector.class 去读取 META-INF/spring.factories 中的自动配置类实现了弱耦合。另外 AutoConfigurationImportSelector.class 实现了 DeferredImportSelector 接口让自动配置的解析晚于主配置的解析 8. Spring 中的设计模式 1. Spring 中的 Singleton 请大家区分 singleton pattern 与 Spring 中的 singleton bean 根据单例模式的目的 Ensure a class only has one instance, and provide a global point of access to it显然 Spring 中的 singleton bean 并非实现了单例模式singleton bean 只能保证每个容器内相同 id 的 bean 单实例当然 Spring 中也用到了单例模式例如 org.springframework.transaction.TransactionDefinition#withDefaultsorg.springframework.aop.TruePointcut#INSTANCEorg.springframework.aop.interceptor.ExposeInvocationInterceptor#ADVISORorg.springframework.core.annotation.AnnotationAwareOrderComparator#INSTANCEorg.springframework.core.OrderComparator#INSTANCE 2. Spring 中的 Builder 定义 Separate the construction of a complex object from its representation so that the same construction process can create different representations 它的主要亮点有三处 较为灵活的构建产品对象 在不执行最后 build 方法前产品对象都不可用 构建过程采用链式调用看起来比较爽 Spring 中体现 Builder 模式的地方 org.springframework.beans.factory.support.BeanDefinitionBuilder org.springframework.web.util.UriComponentsBuilder org.springframework.http.ResponseEntity.HeadersBuilder org.springframework.http.ResponseEntity.BodyBuilder 3. Spring 中的 Factory Method 定义 Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses 根据上面的定义Spring 中的 ApplicationContext 与 BeanFactory 中的 getBean 都可以视为工厂方法它隐藏了 bean 产品的创建过程和具体实现 Spring 中其它工厂 org.springframework.beans.factory.FactoryBean Bean 标注的静态方法及实例方法 ObjectFactory 及 ObjectProvider 前两种工厂主要封装第三方的 bean 的创建过程后两种工厂可以推迟 bean 创建解决循环依赖及单例注入多例等问题 4. Spring 中的 Adapter 定义 Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces 典型的实现有两处 org.springframework.web.servlet.HandlerAdapter – 因为控制器实现有各种各样比如有 大家熟悉的 RequestMapping 标注的控制器实现传统的基于 Controller 接口不是 Controller注解啊的实现较新的基于 RouterFunction 接口的实现它们的处理方法都不一样为了统一调用必须适配为 HandlerAdapter 接口 org.springframework.beans.factory.support.DisposableBeanAdapter – 因为销毁方法多种多样因此都要适配为 DisposableBean 来统一调用销毁方法 5. Spring 中的 Composite 定义 Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly 典型实现有 org.springframework.web.method.support.HandlerMethodArgumentResolverCompositeorg.springframework.web.method.support.HandlerMethodReturnValueHandlerCompositeorg.springframework.web.servlet.handler.HandlerExceptionResolverCompositeorg.springframework.web.servlet.view.ViewResolverComposite composite 对象的作用是将分散的调用集中起来统一调用入口它的特征是与具体干活的实现实现同一个接口当调用 composite 对象的接口方法时其实是委托具体干活的实现来完成 6. Spring 中的 Decorator 定义 Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality 典型实现 org.springframework.web.util.ContentCachingRequestWrapper 7. Spring 中的 Proxy 定义 Provide a surrogate or placeholder for another object to control access to it 装饰器模式注重的是功能增强避免子类继承方式进行功能扩展而代理模式更注重控制目标的访问 典型实现 org.springframework.aop.framework.JdkDynamicAopProxyorg.springframework.aop.framework.ObjenesisCglibAopProxy 8. Spring 中的 Chain of Responsibility 定义 Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it 典型实现 org.springframework.web.servlet.HandlerInterceptor 9. Spring 中的 Observer 定义 Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically 典型实现 org.springframework.context.ApplicationListenerorg.springframework.context.event.ApplicationEventMulticasterorg.springframework.context.ApplicationEvent 10. Spring 中的 Strategy 定义 Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it 典型实现 org.springframework.beans.factory.support.InstantiationStrategyorg.springframework.core.annotation.MergedAnnotations.SearchStrategyorg.springframework.boot.autoconfigure.condition.SearchStrategy 11. Spring 中的 Template Method 定义 Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure 典型实现 大部分以 Template 命名的类如 JdbcTemplateTransactionTemplate很多以 Abstract 命名的类如 AbstractApplicationContext 如有不足请多指教 未完待续持续更新 大家一起进步
http://www.w-s-a.com/news/928396/

相关文章:

  • 网站开发的公司wordpress分类目录 模版
  • flashfxp怎么上传对应网站空间wordpress无法创建
  • 建设网站案例分析做网站代理怎么赚钱
  • 唯品会网站建设特色域名备案期间 网站访问
  • 郑东新区建设局网站怎么做万网网站
  • 阿里云上传的网站 服务器路径试用网站开发
  • 做美食原创视频网站网站开发要多钱
  • 怎么做网站作业哪个网站可兼职做logo
  • asp网站搭建教程做网站备案完成之后需要干什么
  • 无锡外贸网站开发兰州网站在哪备案
  • 广州百度网站建设公司天津建设电工证查询网站
  • 网站建设与管理行业发展情况制作网页动态效果
  • wordpress 特色缩略图临沂seo全网营销
  • 隆昌市住房和城乡建设厅网站做网站用什么字体比较好
  • 惠州网站建设设计18款未成年禁用软件ap入口
  • 班级网站 建设目标如何做好网站建设内容的策划书
  • 网站建设与网页设计期末考试清博舆情系统
  • plone网站开发商城网站建设怎么收费
  • 旺旺号查询网站怎么做公司门户网站项目模版
  • 网站免费一站二站四站上海网站怎么备案表
  • 漫画交流网站怎么做开发微信小程序公司
  • 网站建设马鞍山怎么建立局域网网站
  • 开源 网站开发框架哪些网站可以做图片链接
  • 大良制作网站网站设计的能力要求
  • 前端设计除了做网站还能做什么江苏高校品牌专业建设工程网站
  • 做二手房产网站多少钱用户权限配置wordpress
  • 做亚马逊网站需要租办公室吗小型企业网站模板
  • 网站全屏视频怎么做个人公司注册网上申请
  • 如何k掉别人的网站搜索引擎优化与关键词的关系
  • 百度推广 网站吸引力做网站开发的薪酬怎么样