题目,自己看

Spring设计模式总结

简单工厂

 BeanFactory:Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建
还是传入参数前创建这个要根据具体情况来定。
2、FactoryBean:Spring中的FactoryBean接口的bean是一类叫做factory的bean。其特点是:spring会在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这 个bean.getOjbect()方法的返回值。

工厂方法

FactoryBean:,以Bean结尾,表示它是个Bean,它并不是简单的Bean,而是一个能生产对象或者修饰对象的工厂Bean,spring会在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这个bean.getOjbect()方法的返回值。

单例模式

Spring依赖注入Bean实例默认是单例的。Spring的依赖注入(包括lazy-init方式)都是发生在AbstractBeanFactory的getBean里getBean中的doGetBean方法底层是调用getSingleton进行bean的创建。保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适配器模式

DispatcherServlet根据HandlerMapping返回的handler,向HandlerAdatper发起请求,处理Handler。

HandlerAdapter根据规则找到对应的Handler并让其执行,执行完毕后Handler会向HandlerAdapter返回一个ModelAndView,最后由HandlerAdapter向DispatchServelet返回一个ModelAndView。

HandlerAdatper使得Handler的扩展变得容易,只需要增加一个新的Handler和一个对应的HandlerAdapter即可。因此Spring定义了一个适配接口,使得每一种Controller有一种对应的 适配器实现类,让适配器代替controller执行相应的方法。这样在扩展Controller时,只需要增加一个适配器类就完成了SpringMVC的扩展 了。

代理模式

AOP底层,就是动态代理模式的实现。 动态代理在内存中构建的,不需要手动编写代理类,需要手工编写代理类,代理类引用被代理对象。

切面在应用运行的时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象创建动态的创建一个代理对象。SpringAOP就是以这种 方式织入切面的。

织入:把切面应用到目标对象并创建新的代理对象的过程。

SpringIOC

但是,我们也知道,当程序运行时,用的是具体的UserService对象、OrderService对象,那这些对象是什么时候创建的? 谁创建的? 包括对象里的属性是什么时候赋的值? 谁赋的? 所有这些都是我们程序员做的,以为我们只是写了类而已,所有的这些都是Spring做的,它才是幕后黑手。

这就是控制:1.控制对象的创建2.控制对象内属性的赋值

如果我们不用Spring,那我们得自己来做这两件事,反过来,我们用Spring,这两件事情就不用我们做了,我们要做的仅仅是定义类,以及定义哪些属性需要Spring来赋值(比如某个属性上加@Autowired),而这其实就是第二个问题的答案,这就是反转,表示—种对象控制权的转移。

那反转有什么用,为什么要反转?

如果我们自己来负责创建对象,自己来给对象中的属性赋值,会出现什么情况?

比如,现在有三个类:1.A类,A类里有一个属性C c;

2.B类,B类里也有一个属性Cc;

3.C类

现在程序要运行,这三个类的对象都需要创建出来,并且相应的属性都需要有值,那么除开定义这三个类之外,我们还得写:

  1. A a = new A();

  2. B b = new B();

  3. C c = new C();

  4. a.c = c;

  5. b.c = c;

这五行代码是不用Spring的情况下多出来的代码,而且,如果类在多一些,类中的属性在多一些,那相应的代码会更多,而且代码会更复杂。

lOC表示控制反转,表示如果用Spring,那么Spring会负责来创建对象,以及给对象内的属性赋值,也就是如果用Spring,那么对象的控制权会转交给Spring。

单例bean和单例模式

  

Spring中的事务如何实现

  1. Spring事务底层是基于数据库事务和AOP机制的

  2. 首先对于使用了@Transactional注解的Bean,Spring会创建一个代理对象作为Bean

  3. 当调用代理对象的方法时,会先判断该方法上是否加了@Transactional注解

  4. 如果加了,那么则利用事务管理器创建一个数据库连接

  5. 并且修改数据库连接的autocommit属性为false,禁止此连接的自动提交,这是实现Spring事务非常重要的一步

  6. 然后执行当前方法,方法中会执行sql

  7. 执行完当前方法后,如果没有出现异常就直接提交事务

  8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务

  9. Spring事务的隔离级别对应的就是数据库的隔离级别

  10. Spring事务的传播机制是Spring事务自己实现的,也是Spring事务中最复杂的

  11. Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要新开一个事务,那么实际上就是先建立一个数据库连接,在此新数据库连接上执行sql

//自定义异常
//1.extends Exception
//  1.1 编译期异常,强制需要进行处理
//  1.2 事务不能进行回滚
//2.extends RuntimeException
//  2.1 运行期异常,无需强制进行处理
//  2.2 一旦发生运行期异常,事务可以正常回滚
/**

 * 事务管理
 * 1.编程式事务管理
 * 1.1 取消事务的自动提交 conn.setAutoCommit(false)
 * 1.2 执行业务操作
 * 1.3 catch块 发生异常时,回滚 conn.rollback()
 * 1.4 finally块 必执行,提交  conn.commit() 、 conn.setAutoCommit(true)
 *
 * 2.声明式事务管理
 * @Transcational 对原有的业务逻辑实现增强事务操作
 * 原理:
 * 1.默认使用JDK动态代理、若没有出现接口或者@EnableTransactionManagement(proxyTargetClass = true)属性则转而使用CGLIB动态代理
 * 2.基于AOP完成对业务逻辑的事务操作  TransactionAspectSupport事务管理切面 invokeWithinTransaction() 异常通知、返回通知+执行目标方法
 */


 Spring事务失效的八大场景与原因分析

 * 1.数据库不支持事务  事务型存储引擎InnoDB
 *
 * 2.方法是private的: Spring事务会基于CGLIB来进行AOP,而CGLIB会基于父子类来失效,子类是代理类,父类
 * 是被代理类,如果父类中的某个方法是private的,那么子类就没有办法重写它,也就没有办法额外增加Spring事务的逻辑。
 *
 * 3.方法是final的:原因和private是一样的,也是由于子类不能重写父类中的final的方法
 *
 * 4.异常被吃掉:如果Spring事务没有捕获到异常,那么也就不会回滚了,默认情况下Spring会捕获RuntimeException和Error。
 *
 * 5.类没有被Spring管理
 *
 * 6.单独的线程调用方法:当Mybatis或JdbcTemplate执行SQL时,会从ThreadLocal中去获取数据库连接对象,
 * 如果开启事务的线程和执行SQL的线程是同一个,那么就能拿到数据库连接对象,
 * 如果不是同一个线程,那就拿到不到数据库连接对象,这样,Mybatis或JdbcTemplate就会自己去新建一个数据库连接用来执行SQL,
 * 此数据库连接的autocommit为true,那么执行完SQL就会提交,后续再抛异常也就不能再回滚之前已经提交了的SQL了。
 *
 * 7.没加@Configuration注解:如果用SpringBoot基本没有这个问题,但是如果用的Spring,那么可能会有这个问题,
 * 这个问题的原因其实也是由于Mybatis或JdbcTemplate会从ThreadLocal中去获取数据库连接,
 * 但是ThreadLocal中存储的是一个ThreadLocalMap,ThreadLocalMap的key为DataSource对象,value为连接对象,而如果我们没有在ApplicationConfig上添加@Configuration注解的话,
 * 会导致MAP中存的DataSource对象和Mybatis和JdbcTemplate中的DataSource对象不相等,从而也拿不到数据库连接,导致自己去创建数据库连接了。
 *
 * 8.方法内的自调用: Spring事务是基于AOP的,只要使用代理对象调用某个方法时,Spring事务才能生效,
 * 而在一个方法中调用使用this.xxx()调用方法时,this并不是代理对象,所以会导致事务失效。
 *  a.解放办法1:把调用方法拆分到另外一个Bean中
 *  b.解决办法2:自己注入自己
 *  c.解决办法3:AopContext.currentProxy()+@EnableAspectJAutoProxy(exposeProxy = true)
 */

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值