一、SpringMVC工作原理
- 用户发送请求至web服务器,web服务器根据web.xml配置匹配到DispatcherServlet。
- DispatcherServlet会根据HandlerMapping、HandlerAdapter会找到对应的Handler处理器
- Handler处理器处理请求后返回ModelAndView逻辑视图给DispatcherServlet,DispatcherServlet根据ViewReslover视图解析器将ModelAndView解析成真正视图,然后返回给用户
<mvc:annotation-driven /> 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean。
第一个是HandlerMapping的实现类,它会处理@RequestMapping 注解,并将其注册到请求映射表中。
第二个是HandlerAdapter的实现类,它是处理请求的适配器,说白了,就是确定调用哪个类的哪个方法,并且构造方法参数,返回值。
二、Spring中ApplicationContext和beanfactory区别
1)ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。
ApplicationContext包还提供了以下的功能
- 提供了支持国际化的文本消息
- 统一的资源文件读取方式
- 已在监听器中注册的bean的事件
以下是三种较常见的 ApplicationContext 实现方式:
- ClassPathXmlApplicationContext:从classpath的XML配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”);
- FileSystemXmlApplicationContext :由文件系统中的XML配置文件读取上下文ApplicationContext context = new FileSystemXmlApplicationContext(“bean.xml”);
- XmlWebApplicationContext:由Web应用的XML文件读取上下文。
三、Spring的beanFactory和factoryBean的区别
BeanFactory是spring中比较原始的Factory。提供了IOC容器最基本的形式。FactoryBean可以说为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,可以在getObject()方法中灵活配置
四、SpringIOC和AOP原理
4.1 IoC(Inversion of Control)
(1). IoC(Inversion of Control)是控制权由应用代码中转到了外部容器,控制反转。IoC还有另外一个名字——“依赖注入(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。
(2). 依赖注入的思想是通过反射机制实现的
例:如下spring配置
<bean id="courseDao" class="com.qcjy.learning.Dao.impl.CourseDaoImpl"></bean>
//解析<bean .../>元素的id属性得到该字符串值为“courseDao”
String idStr = "courseDao";
//解析<bean .../>元素的class属性得到该字符串值为“com.qcjy.learning.Dao.impl.CourseDaoImpl”
String classStr = "com.qcjy.learning.Dao.impl.CourseDaoImpl";
//利用反射知识,通过classStr获取Class类对象
Class<?> cls = Class.forName(classStr);
//实例化对象
Object obj = cls.newInstance();
//container表示Spring容器
container.put(idStr, obj);
IoC的优点:降低了组件之间的耦合,降低了业务对象之间替换的复杂性,使之能够灵活的管理对象。
4.2 AOP(Aspect Oriented Programming)
(1) AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等
(2) 实现AOP的技术:
- 静态代理的代表为AspectJ
- 动态代理则以Spring AOP为代表
(3) 与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。Spring AOP根据被代理的类是否实现了一个接口,是则选择JDK动态代理,反之则选择CGLIB动态代理
- JDK动态代理:核心是
InvocationHandler
接口和Proxy
类。通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口,在运行期间创建一个接口的实现类来完成对目标对象的代理。。 - CGLIB动态代理:核心是MethodInterceptor接口和Enhancer类。CGLIB是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为
final
,那么它是无法使用CGLIB做动态代理的。性能比JDK强;需要引入包asm.jar和cglib.jar。
(4) spring aop两种配置方式 :1、注解配置AOP 2、xml配置aop
(5)xml配置案例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
"><!-- 要添加最后2行 -->
<context:annotation-config />
<context:component-scan base-package="com.oumyye"/>
<bean id="logInterceptor" class="com.oumyye.aop.LogInterceptor"></bean>
<aop:config>
<aop:pointcut expression="execution(public * com.oumyye.service..*.add(..))"
id="servicePointcut"/>
<aop:aspect id="logAspect" ref="logInterceptor">
<aop:before method="before" pointcut-ref="servicePointcut" />
</aop:aspect>
</aop:config>
</beans>
(7).Spring切面可以应用五种类型的通知
- before:前置通知,在一个方法执行前被调用。
- after: 在方法执行之后调用的通知,无论方法执行是否成功。
- after-returning: 仅当方法成功完成后执行的通知。
- after-throwing: 在方法抛出异常退出时执行的通知。
- around: 在方法执行之前和之后调用的通知。
详情访问https://blog.csdn.net/qq_33314107/article/details/79468826
https://blog.csdn.net/qq_33314107/article/details/79468505
五、Spring注入方式
- 构造方法注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。
- Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。
- 基于注解的注入
六、Spring事务管理
Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。Spring事务管理器的接口是PlatformTransactionManager,PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法根据指定的传播行为、隔离级别返回当前活动的事务或创建一个新的事务
6.1 Spring支持两种类型的事务管理:
- 编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
- 声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。
6.2 Spring事务的传播行为
- propagation_required:如果当前没有事务,就新建一个事务。这是最常见的选择,也是Spring默认的事务的传播。
- propagation_requires_new:新建事务,如果当前存在事务,把当前事务挂起(暂停等待)。
- propagation_supports:如果当前没有事务,就以非事务方式执行。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- propagation_mandatory:如果当前没有事务,就抛出异常。
- propagation_never:以非事务方式执行,如果当前存在事务,则抛出异常
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与propagation_required类似的操作
6.3 Spring事务的隔离级别
- ISOLATION_DEFAULT:这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应
- ISOLATION_READ_UNCOMMITTED:这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。
- ISOLATION_READ_COMMITTED:保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
- ISOLATION_REPEATABLE_READ:这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻读。
- ISOLATION_SERIALIZABLE:这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读
6.4 并发事务引起的问题
- 脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
- 不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
- 幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。
7、Spring bean生命周期
- Spring容器 从XML 文件中读取bean,并实例化bean。
- Spring根据bean的定义填充所有的属性。
- 如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法。
- 如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。
- 如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。
- 如果bean实现InitializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用初始化方法。
- 如果有任何与bean相关联的BeanPostProcessors,这些bean的postProcessAfterInitialization() 方法将被调用。
- 如果bean实现了 DisposableBean,它将调用destroy()方法。
8、Spring Bean的作用域
Spring容器中的bean可以分为5个范围。全局作用域与Servlet中的session作用域效果相同
- singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护。
- prototype:原形范围与单例范围相反,为每一个bean请求提供一个实例。
- request:在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
- Session:与请求范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
- global-session:global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。
9、Spring Bean的自动装配
不需要<constructor-arg>和<property>配置,能通过Bean工厂自动处理bean之间的协作。有如下方式:
- no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
- byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
- byType::通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
- constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
- autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
自动装配的局限性是:
- 重写: 你仍需用 <constructor-arg>和 <property> 配置来定义依赖,意味着总要重写自动装配。
- 基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
- 模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。
十、Spring常用注解
使用注解之前要开启自动扫描功能,其中base-package为需要扫描的包(含子包)。
<context:annotation-config/>
<context:component-scan base-package="cn.test"/>
@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件、
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上)
@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
@Autowired @Qualifier("personDaoBean") 存在多个实例配合使用
@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@PostConstruct 初始化注解
@PreDestroy 摧毁注解 默认 单例 启动就加载
@Async异步方法调用
十一、问题总结
1、Spring框架中的单例bean是线程安全的吗?
不,Spring框架中的单例bean不是线程安全的
2、Spring中如何注入一个java集合?
Spring提供以下几种集合的配置元素:
- <list>类型用于注入一列值,允许有相同的值。
- <set> 类型用于注入一组值,不允许有相同的值。
- <map> 类型用于注入一组键值对,键和值都可以为任意类型。
- <props>类型用于注入一组键值对,键和值都只能为String类型。
3、Spring如何处理线程并发问题?
Spring使用ThreadLocal解决线程安全问题,ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal