Spring-依赖注入、切面
【064 什么是Spring?】
Spring本质上是一个轻量级开发框架,包含的内容非常多,最核心的实际上是IOC控制反转,实现一个Bean容器;在此基础上,提供AOP面向切面编程机制和基于AOP的Aspect切面,还有搭建Web应用的Spring MVC框架,和数据库交互的Data Access等各方面内容,并能快速整合Struts、Mybatis等框架。
【065 什么是IOC?】
传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,而Spring中有一个专门的容器来创建管理对象,由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象。说的简单一点,把对象的创建、初始化、销毁交给spring来管理,而不是由开发者控制。
【066 Spring怎样进行Bean的管理?】
核心是BeanFactory接口,子接口ApplicationContext,子类WebApplicationContext真正实现了Spring的上下文环境,通过BeanDefinitionParser的实现类,从xml文件和注解中加载所有Bean,并封装成BeanDefinition,注册到Map beanDefinitionMap中,key值是Bean的全路径类名,Map是一个ConcurrentHashMap。根据类的属性决定何时从map中取出BeanDefinition并实例化。
【067 BeanFactory和ApplicationContext的区别】
①BeanFactory是Spring中最底层的接口,提供了最简单的容器的功能,即bean生命周期的控制方法;
②ApplicationContext继承了BeanFactory接口,同时提供的额外的功能,如国际化的功能,消息发送、响应机制,统一加载资源的功能,强大的事件机制,对Web应用的支持等;常用实现类:ClassPathXmlApplicationContext、XmlWebApplicationContext。
③加载方式不同:BeanFactory采用的是延迟加载的形式来注入Bean,即只有在使用某个bean的时候,才对该Bean进行加载实例化;而ApplicationContext是在Ioc容器启动时就一次性创建所有的Bean,这样的好处是可以马上发现Spring配置文件中的错误。
【067扩展Spring的国际化】
MessageSource接口,用于支持信息的国际化。ApplicationContext接口继承了MessageSource接口,对MessageSource的实现都是自身所持有的MessageSource类型的messageSource对象来实现的,源码显示如果bean容器中存在名为messageSource的bean,则取该bean作为messageSource。Spring MVC的拦截器LocaleChangeInterceptor会更新请求的Local。
【068 Spring的配置方式】
①基于XML的配置:<beans>开头,然后一系列的bean定义和专门的应用配置选项组成;
②基于注解的配置:<context:component-scan/>+注解标签的方式;
③基于Java的配置:由@Configuration注解和@Bean注解来实现,@Bean声明的方法所起到的作用与元素类似,@Configuration所注解的类则表示这个类的主要目的是作为bean定义的资源。
【068扩展1 Bean的依赖注入方式】
注入的方式有三种:构造器(<constructor-arg index="0" ref="userDao">)、Setter方法(<property name="userDao" ref="userDao">)和注解@Autowire。注解是目前最常用的,而构造器和Setter方法都是基于XML配置的,如果不使用注解,对于依赖关系无需变化的注入,尽量采用构造注入;而其他的依赖关系的注入,则考虑采用Setter注入。
【068扩展2 context:annotation-config与context:component-scan的区别】
annotation-config处理@autowired之类的注解,前提是注解依赖的类已经被注册到spring容器里;component-scan除了包含annotation-config的作用外,还能自动扫描和注册base-package下有@component之类注解的类,将其作为bean注册到spring容器里。
【068扩展3 常用的注解】
①@Component、@Controller、@Service,后面两个是@Component的子标注,没有添加新的内容,只是用于区分component的含义;
②@Autowired、@Qualifier、@Resource,其中@Resource是Java的注解,默认按照name匹配来注入,可以通过修改Type=byType来指定按照类型注入;而@Autowired和@Qualifier是Spring的注解,@Autowired默认按照类型注入,可以通过@Qualifier指定名称匹配。
【068扩展4 xml文件的自动装配】
①no,默认的方式是不进行自动装配,通过设置ref属性来进行装配;
②constructor,要提供给构造器参数,如果没有构造器参数类型,将会抛出异常;
③byName,通过参数名自动装配,bean的autowire属性被设置成byname,容器试图匹配、装配和该bean的属性具有相同名字的bean;
④byType,通过参数类型自动装配bean的autowire属性被设置成byType,容器试图匹配、装配和该bean的属性具有相同类型的bean,如果有多个bean符合条件,则抛出错误;
⑤autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
【069 Bean的作用域Scope】
①singleton:是默认的,确保不管接受到多少个请求,每个容器中只有一个bean的实例,其生命周期由beanFactory来维护;
②prototype:原形范围与单例范围相反,为每一个bean请求提供一个实例,bean的创建由beanFactory来管理,但消亡要程序自身控制;
③request:在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收;
④ Session:确保每个session中有一个bean的实例,在session过期后,bean会随之失效;
⑤ global-session:当应用部署在Portlet容器中工作时,如果想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。
【069扩展1 注解如何设置Scope】
@Scope可以指定作用域,默认是单例的。
【069扩展2 Spring框架中的单例Beans是线程安全的么?】
不是。Spring框架并没有对单例bean进行任何多线程的封装处理,但实际上,大部分的Spring bean并没有可变的状态(比如Service类和DAO类)。同时,Spring对一些Bean,如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态。
【070 Bean的生命周期】
Bean的生命周期方法可以分为容器方法、Bean自身方法和Bean生命周期方法。简化版:
①容器方法会在实例化Bean对象时最先调用,用于修改BeanDefinition的参数,如数据库连接池datasource下的${jdbc.url}等;
②执行Bean自身的构造器方法和属性注入方法;
③如果Bean类实现了BeanNameAware接口,则执行其setBeanName方法;
④如果Bean类实现了BeanFactoryAware接口,则执行其setBeanFactory方法,上述两个方法是生命周期方法,为了使Bean知道创建自己的工厂和在工厂中的ID,可以自行管理;
⑤调用定义的的初始化方法“init-method”(!!注意,init-method方法没有参数);
⑥此外,还会有生命周期的方法,诸如Before/AfterPostProcessor和AfterPropertiesSet等;
⑦容器关闭,如果Bean类实现了DisposableBean接口,则执行它的destroy()方法;
⑧ 调用定义的的初始化方法“destroy-method”,销毁Bean。
【071 什么是AOP?】
AOP是面向切面的编程,至少要明确pointcut和advice,可以通过@Aspect注解或表达式等声明AOP,例如Spring的事务expression="execution(* com.cmcc.sleepmult.service.*.*(..))",*分别代表了方法的访问权限,service的任意子包和任意方法。
【071扩展 advice的类型有哪些?】
① 前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点的执行,除非抛出异常;
② 返回后通知(After returning advice):在某连接点正常完成后执行的通知:
③ 抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知;
④后通知(After finally advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出);
⑤环绕通知(Around Advice):包围一个连接点的通知,事务就是这种通知。
【072 Spring的事务管理】
Spring的事务是在业务层级别上进行管理的,通过DataSourceTransactionManager进行session的commit和rollback。实现了CGLib代理的形式,对service的方法使用try-catch代码块。事务的形式在tx:advice标签下设置,不同的方法可以指定不同的事务级别,最常用的事务是REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务;此外还有SUPPORTS、REQUIRES_NEW、NEVER等。