IOC
描述下Spring IOC容器的初始化过程
Spring IOC容器的初始化简单的可以分为三个过程:
第一个过程是Resource资源定位。这个Resouce指的是BeanDefinition的资源定位。这个过程就是容器找数据的过程,就像水桶装水需要先找到水一样。
第二个过程是BeanDefinition的载入过程。这个载入过程是把用户定义好的Bean表示成Ioc容器内部的数据结构,而这个容器内部的数据结构就是BeanDefition。
第三个过程是向IOC容器注册这些BeanDefinition的过程,这个过程就是将前面的BeanDefition保存到HashMap中的过程。
AOP
某段代码动态切入到指定方法的指定位置
- 切面(Aspect): 指关注点模块化,这个关注点可能会横切多个对象。事务管理是企业级Java应用中有关横切关注点的例子。 在Spring AOP中,切面可以使用通用类基于模式的方式(schema-based approach)或者在普通类中以
@Aspect注解(@AspectJ 注解方式)来实现。 - 连接点(Join point): 在程序执行过程中某个特定的点,例如某个方法调用的时间点或者处理异常的时间点。在Spring AOP中,一个连接点总是代表一个方法的执行。
- 通知(Advice): 在切面的某个特定的连接点上执行的动作。通知有多种类型,包括“around”, “before” and “after”等等。通知的类型将在后面的章节进行讨论。 许多AOP框架,包括Spring在内,都是以拦截器做通知模型的,并维护着一个以连接点为中心的拦截器链。
- 切点(Pointcut): 匹配连接点的断言。通知和切点表达式相关联,并在满足这个切点的连接点上运行(例如,当执行某个特定名称的方法时)。切点表达式如何和连接点匹配是AOP的核心:Spring默认使用AspectJ切点语义。
- 引入(Introduction): 声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被通知的对象上。例如,可以使用引入来使bean实现
IsModified接口, 以便简化缓存机制(在AspectJ社区,引入也被称为内部类型声明(inter))。 - 目标对象(Target object): 被一个或者多个切面所通知的对象。也被称作被通知(advised)对象。既然Spring AOP是通过运行时代理实现的,那么这个对象永远是一个被代理(proxied)的对象。
- AOP代理(AOP proxy):AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
织入(Weaving): 把切面连接到其它的应用程序类型或者对象上,并创建一个被被通知的对象的过程。这个过程可以在编译时(例如使用AspectJ编译器)、类加载时或运行时中完成。 Spring和其他纯Java AOP框架一样,是在运行时完成织入的。
应用
在实际的生产环境中,更多的时候使用通配符的方式
1、可以用来匹配一个或者多个字符
execution( public Integer com.mashibing.service.MyCalculator.(Integer,Integer)
2、匹配任意类型的参数,只能匹配一个
execution( public Integer com.mashibing.service.MCalculator.(Integer,))
3、在进行匹配的时候只能匹配一层路径,不能匹配多层
4、不能够匹配访问修饰符,如果不确定访问修饰符是什么,可以直接省略不写
execution( Integer com.mashibing.service.MyCalculator.(Integer,))
5、返回值可以使用来代替
..:
1、可以匹配多个参数,任意类型
execution( com.mashibing.service.MyCalculator.(..))
2、可以匹配多层路径
execution( com.mashibing..MyCalculator.(..))
最偷懒的方式:
execution( (..))
execution( com..(..))
如果表达式是以*开头,那么可以代替所有在使用表达式的时候还支持逻辑运算<br /> &&:多个条件必须同时满足<br /> execution(public Integer com.mashibing.service.MyCalculator.*(..)) && execution(* *(..))<br /> ||:多个条件只要满足其中一个即可<br /> execution(public Integer com.mashibing.service.MyCalculator.*(..)) || execution(* *(..))<br /> !:取反,除了这种情况的其他都满足<br /> !execution(public Integer com.mashibing.service.MyCalculator.add(Integer,Integer))使用通配符的时候不是越简洁越好,更多的是要选择符合要求或者符合规则的匹配方式,<br /> 此时就要求在定义标识符的时候必须要遵循项目规范通知的正常执行顺序:<br /> 如果正常执行:@Before--》@After----》@AfterReturning<br /> 如果异常结束:@Before--》@After----》@AfterThrowing
如果想要在方法中获取对应的参数或者方法名称等信息的时候,必须要使用JoinPoint对象,并且此参数必须是第一个<br /> getSignature()<br /> getArgs()<br /> 如果方法中有返回值,那么必须要在注解中添加 Returing="result" ,这个result必须要和参数列表中的参数名称保持一致<br /> 如果需要添加异常信息,那么在注解中要添加Throwing="e" 这个e的名称必须跟参数列表中的名称保持一致<br /> 如果想要添加其他参数,必须要添加args(参数列表),ArgNames(参数列表)<br /> @Before(value = "execution(public Integer com.mashibing.service.MyCalculator.*(Integer,Integer)) && args(joinPoint,k)",argNames = "joinPoint,k")
通知方法在定义的时候有没有什么特殊的要求?<br /> 通知方法在定义的时候对于访问修饰符、返回值类型都没有明确的要求,<br /> 但是要注意,参数不能随便添加
如果有多个匹配的表达式相同,能否做抽象?<br /> 定义一个没有返回值的空方法,给该方法添加@PointCut注解,后续在使用的时候可以直接调用方法名称<br /> 此处的方法只是起一个声明的作用,能够供内部的其他通知方法进行调用
环绕通知:<br /> 环绕通知在执行的时候是优先于普通通知的<br /> 如果是正常结束,那么执行顺序是:<br /> 环绕前置通知--》@Before--》环绕后置通知--》环绕返回通知--》@After--》@AfterReturning<br /> 如果是异常结束,那么执行顺序是:<br /> 环绕前置通知--》@Before--》环绕异常通知--》环绕返回通知--》@After--》@AfterReturing<br /> 如果出现异常的时候,在环绕通知中解决了,那么普通通知是接受不到的,如果想让普通通知接收到需要进行抛出 throw throwable<br /> 执行顺序改为:<br /> 环绕前置通知--》@Before--》环绕异常通知--》环绕返回通知--》@After--》@AfterThrowing
当应用程序中包含多个切面类的时候,具体的执行顺序是什么样?<br /> 按照切面类的名称的首字母进行排序操作,按照字典序<br /> 如果需要认为的规定顺序,可以在切面类上添加@Order注解同时可以添加具体的值<br /> 值越小,越优先
声明式事务
<!--配置事务管理器的bean对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启基于注解的事务管理器的配置-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
propagation:
传播特性:表示不同的事务之间执行的关系
| PROPAGATION_REQUIRED | 如果有事务运行,当前的方法就在这个事务内运行,否则就启动一个新事务,并在自己的事务内运行 |
|---|---|
| PROPAGATION_REQUIRES_NEW | 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起 |
| PROPAGATION_SUPPORTS | 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行 |
| PROPAGATION_MANDATORY | 果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常 |
| PROPAGATION_NOT_SUPPORTED | 总是非事务地执行,并挂起任何存在的事务 |
| PROPAGATION_NEVER | 总是非事务地执行,如果存在一个活动事务,则抛出异常 |
| PROPAGATION_NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行 |
1、PROPAGATION_REQUIRED: 如果有事务运行,当前的方法就在这个事务内运行,否则就启动一个新事务,并在自己的事务内运行
2、PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
3、PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4、PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5、PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。
6、PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
7、PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行
isolation:隔离级别:4种隔离级别,会引发不同的数据错乱问题
| 隔离级别 | 脏读(Dirty Read) | 幻读(Phantom Read) |
|---|---|---|
| 未提交读(Read uncommitted) | 可能 | 可能 |
| 已提交读(Read committed) | 不可能 | 可能 |
| 可重复读(Repeatable read) | 不可能 | 可能 |
| 可串行化(Serializable ) | 不可能 | 不可能 |
timeout:超时时间,<br /> readonly:只读事务:如果配置了只读事务,那么在事务运行期间,不允许对数据进行修改,否则抛出异常<br /> <br /> 设置哪些异常不会回滚数据<br /> noRollBackfor: noRollbackFor = {ArithmeticException.class}<br /> noRollbackForClassName:<br /> <br /> 设置哪些异常回滚<br /> rollBackfor:<br /> rollbackForClassName
XML配置事务
<aop:config>
<aop:pointcut id="txPoint" expression="execution(* com.mashibing.service.*.*(..))"/>
<!--事务建议:advice-ref:指向事务管理器的配置-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="txPoint"></aop:advisor>
</aop:config>
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<!--事务属性-->
<tx:attributes>
<!--指明哪些方法是事务方法-->
<tx:method name="*"/>
<tx:method name="checkout" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
动态代理
SpringMVC
执行流程

1、DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
2、HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
3、返回处理器执行链,根据url查找控制器,并且将解析后的信息传递给DispatcherServlet
4、HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
5、执行handler找到具体的处理器
6、Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
7、HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
8、DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
9、视图解析器将解析的逻辑视图名传给DispatcherServlet。
10、DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图,进行试图渲染
11、将响应数据返回给客户端
