spring + mybatis笔记

1.将一个类声明为Bean的注解:

1.@component:通用的注解,可以标注任意类为spring组件。如果一个Bean不知道属于哪个层,可以使用@Component注解标注;

2.@Repository / @Mapper:对应持久层(DAO层),主要用于数据库相关操作;二者的区别在于它们实现持久化数据访问的方式不同,前者基于ORM框架封装了一些常用的CRUD操作和查询方法,使用方便;Mapper基于注解或XML配置,提供了更细粒度的SQL控制能力,更加灵活。此外,两者的接口定义和实现方式也不同。Repository是一个接口,Spring Data会动态生成它的实现类;Mapper是一个java类,使用它后,MyBatis会基于注解或XML配置生成和维护它的实现类。单独使用@Repository需要配合@MapperScan注解。

3.@Service:对应服务层;

4.@Controller:对应SpringMvc控制层,主要用于接受用户请求并调用Service层返回数据给前端页面;

2.Bean的线程安全问题:

Spring框架中的bean是否线程安全,取决于其作用域和状态。

以最常用的singleton和prototype为例。prototype作用域下,每次获取都会创建一个新的bean对象,不存在资源竞争,也就不存在线程安全问题。singleton作用域下,IOC容器中只有唯一的bean实例,可能会存在资源竞争问题。如果bean是有状态的话,那就存在线程安全问题(有状态是指包含可变的成员变量的对象)。

对于有状态的单例Bean的线程安全问题,常见的解决办法有两种:一是在Bean中尽量避免定义可变的成员变量;二是在类中定义一个ThreaLocal成员变量,将需要的可变成员变量保存ThreadLocal中。

3.各类注解

1.@RequestParam:作用是将请求参数绑定到方法的参数上。可以添加三个属性。value:指定请求参数的名称,如果请求参数与方法参数相同,则可以省略。required:true/false,指定该请求参数是否可选。defaultvalue:指定请求参数不传时,方法中参数的默认值。

4.什么是AOP?Spring中的事务是如何实现的?

  1. AOP:称为面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”,减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。
  2. 常用到AOP的场景包括记录操作日志、缓存、Spring实现的事务等。以记录日志为例,核心是:使用AOP中的环绕通知+切点表达式(找到要记录日志的方法),通过环绕通知的参数获取请求方法的参数(类、方法、注解、请求方式等),获取到这些参数以后,保存到数据库。
  3. Spring事务的本质是通过AOP功能,对方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

5.Spring中事务失效的场景?

  1. 异常捕获处理:事务通知只有捕捉到了目标抛出的异常,才能进行后续的回滚操作,如果目标自己处理掉异常,事务通知无法洞悉也就无法回滚了。解决的办法是在catch块添加throw new RuntimeException(e)抛出。
  2. 抛出检查异常:因为Spring默认只会回滚非检查异常,所以即使抛出了异常,但因为异常属于检查异常,还是会导致事务失效。解决办法是配置rollbackFor属性,即在transactional注解后加上(rollbackFor=Exception.class),即只要抛出异常,都会被捕获;
  3. 非public方法导致事务失效:因为Spring为方法创建代理,添加事务通知,前提条件都是该方法是public的,解决办法就是将该方法改为public。

6.@Autowired和@Resource的区别?

  1. 前者是Spring提供的注解,后者是JDK提供的注解;
  2. 前者默认按照byType类型注入,后者默认按照ByName名称注入;
  3. 当一个接口存在多个实现类时。二者都需要通过具体的名称才能匹配到对应的Bean。前者通过@Qualifier。后者通过name属性显式指定名称。
  4. 前者支持在字段、构造函数、方法和参数上使用,后者主要用于字段和方法上的注入,不支持在构造函数和参数上使用。

7.Bean的生命周期?

  1. 创建Bean的实例:Bean容器首先会找到配置文件中的Bean定义,然后使用Java反射API来创建Bean的实例(会生成一个BeanDefinition);
  2. Bean属性的赋值和填充:为Bean设置相关属性和依赖,例如@Autowired注入的对象,@Value注入的值,setter方法和或构造函数注入依赖和值、@Resource注入的各种资源。
  3. Bean初始化:

                如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字;

                如果 Bean 实现了 BeanClassLoader 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。

                如果Bean实现了BeanFactoryAware接口,调用setBeanFactory()方法,传入BeanFactory对象的实例。

                如果实现了其他*.Aware接口,就调用相应的set方法。

                如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。

                如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。

                如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessAfterInitialization()方法。

4.销毁Bean:销毁并不是马上将Bean销毁掉,而是把Bean的销毁方法先记录下来,将来需要销毁Bean或者销毁容器的时候,就调用这些方法去释放Bean所持有的资源。

        如果Bean实现了DisposableBean接口,执行destroy()方法。

        如果Bean在配置文件中的定义包含destroy-method属性,执行指定的Bean销毁方法,或者也可以直接通过@PreDestroy注解标记Bean销毁之前执行的方法。

8.SpringMVC

1.MVC是模型(model)、视图(view)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。

2.SpringMVC的核心组件:

  • DispatchServlet:核心中央处理器,负责接收请求,分发,并给予客户端响应。
  • HandlerMapping:处理器映射器,根据url去匹配查找能处理的Handler,并会将请求涉及到的拦截器一起封装。
  • HandlerAdapter:处理器适配器,根绝HandlerMapping找到的Handler,适配执行对应的Handler;
  • Handler:请求处理器,处理实际请求的处理器。
  • viewResolver:视图解析器,根据Handler返回的逻辑视图/视图,解析并渲染真正的视图,并传递给DispatchServlet响应客户端。

流程说明(重要):

  1. 客户端(浏览器)发送请求,DispatcherServlet拦截请求。
  2. DispatcherServlet根据请求信息调用 HandlerMapping 。HandlerMapping 根据 URL 去匹配查找能处理的 Handler(也就是我们平常说的 Controller控制器),并会将请求涉及到的拦截器和 Handler一起封装。
  3. DispatcherServlet调用HandlerAdapter适配器执行 HandlerAdapter。
  4. Handler完成对用户请求的处理后,会返回一个ModelAndView 对象给DispatcherServlet,ModelAndView 顾名思义,包含了数据模型以及相应的视图的信息。Model是返回的数据对象,View 是个逻辑上的 View 。
  5. ViewResolver会根据逻辑 View 查找实际的 View 。
  6. DispatcherServlet把返回的 Model 传给 View 视图渲染)。
  7. 把 View 返回给请求者(浏览器)

 9.统一异常处理怎么做?

        推荐使用注解的方式进行统一异常处理,具体会使用到@ControllerAdvice + @ExceptionHandler这两个注解。在这种异常处理方式下,或给所有或者指定的Controller织入异常处理的逻辑(AOP),当Controller中的方法抛出异常时,由被@ExceptionHandler注解修饰的方法进行处理。

        ExceptionHandlerMethodResolver中getMappedMethod方法决定了异常具体被哪个被@ExceptionHandler注解修饰的方法进行异常处理。它的源代码可以看出:getMappedMethod()会首先找到可以匹配处理异常的所有方法,将它们放到一个ArrayList容器中,然后对其进行从小到大的排序,最后取最小的那一个匹配的方法。(即匹配度最高的那个)

10.Spring框架中用到了哪些设计模式?

工厂设计模式:Spring使用工厂模式通过BeanFactory、ApplicationContext创建bean对象。

代理设计模式:Spring AOP功能的实现;

单例设计模式:Spring中的Bean默认都是单例的;

模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以template结尾的对数据库操作的类,它们使用到了模板方法设计模式;

11.Spring中的循环依赖与解决?

1.定义:循环依赖是指Bean对象循环引用,是两个或多个Bean之间持有对方的引用,如A依赖B,在B中又有对A的依赖;

2.解决:Spring框架通过使用三级缓存来解决这个问题;

        1.一级缓存:存放最终形态的Bean(已经实例化、属性填充、初始化),单例池,为Spring的单例属性而生,一般情况下Bean都是从这里获取的,但并不是所有的Bean都在单例池里,例如原型Bean就不在其中。

        2.二级缓存:存放过渡Bean(半成品,尚未属性填充),也就是三级缓存中ObjectFactory产生的对象,与三级缓存配合使用,可以防止在AOP的情况下,每次调用ObjetFactory中的getOnject方法产生新的对象;

        3.三级缓存:存放ObjectFactory,objectFactory中的getObject方法可以生成原始Bean对象或者代理对象(如果Bean被AOP代理)。三级缓存只会对单例Bean生效。

        如果发生循环依赖的话,就去 三级缓存 singletonFactories中拿到三级缓存中存储的 ObjectFactory 并调用它的getObject方法来获取这个循环依赖对象的前期暴露对象(虽然还没初始化完成,但是可以拿到该对象在堆中的存储地址了),并且将这个前期暴露对象放到二级缓存中,这样在循环依赖时,就不会重复初始化了,不过,这种机制也有缺点,需要维护三个map,增加了内存开销,降低了性能,并且还有少部分情况是不支持循环依赖的,比如非单例的Bean和@Async注解的Bean无法支持循环依赖。

12.Lazy能解决循环依赖吗?

        @Lazy用来标记类是否需要懒加载/延迟加载,可以作用在类上、方法上、构造器上、方法参数上、成员变量中。如果一个类没有被标记为懒加载,那么它会在SpringIOC容器启动的过程中被创建和初始化,如果一个Bean被标记为懒加载,那么它会等到第一次被请求时才创建,这可以帮助减少应用启动的初始化时间,也可用于解决循环依赖问题。

        Lazy注解是如何解决循环依赖的?

比如有两个Bean A 和 B,它们之间发生了循环依赖,那么在A的构造器上添加@Lazy注解后(延迟B的实例化),加载的流程如下:

  • 首先Spring会去创建A的Bean,创建时需要注入B的属性;
  • 由于A上标注了Lazy注解,因此Spring会去创建一个B的代理对象,将这个代理对象注入到A中的B属性;
  • 之后开始执行B的实例化、初始化。在注入B中的A属性时,此时A已经创建完毕了,就可以将A给注入进去。

这样,就解决了循环依赖问题,关键在于对A中的B属性进行注入时,注入的是B的代理对象,因此不会发生循环依赖。

 


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值