0 复习
- FactoryBean技术(用于创建复杂对象)
复杂对象:底层不能直接通过new构造方法创建,通常需要若干步骤才能创建的对象。比如:Connection、SqlSession
- 编码 implements FactoryBean
- 配置 通过bean标签配置
- 配置文件
- import标签
- xsd使用规则
- 拆分jdbc.properties文件
- 概念总结 IOC和DI
- Spring整合Struts2 导入依赖:spring-web struts2-spring-plugin
web.xml 在tomcat启动应用时,创建Spring工厂
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
- 注解开发 Component(Controller、Service、Repository)替换bean标签 Autowired替换property标签
Spring AOP
1 代理设计模式
1.1 解决的问题
要不要在业务层中定义额外功能?
业务调用者的角度:需要,业务方法中需要使用这些额外功能 软件设计者的角度:不需要,定义后会造成代码的频繁修改
矛盾的解决方案:代理模式
1.2 代理模式
矛盾:
房东不愿意提供额外功能(带看房,车接车送),因为麻烦 租客必须要使用这些额外功能
矛盾的解决方案:中介
中介代理了房东的出租房屋的方法,同时提供额外的功能。 房东无需亲自和租客打交道,节省时间。租客也可以享受完整的服务。
在程序中,Action(租客) 和 Serivce(房东) 的矛盾,也可以通过添加一个代理类解决。
1.3 静态代理
实战:
接口:
代码语言:javascript复制public interface UserService {
public boolean login(String username,String password);
public void removeUser(Integer id);
}
原始实现类:
代码语言:javascript复制public class UserServiceImpl implements UserService {
@Override
public boolean login(String username, String password) {
System.out.println("username = [" username "], password = [" password "]");
return false;
}
@Override
public void removeUser(Integer id) {
System.out.println("id = [" id "]");
}
}
代理实现类:
代码语言:javascript复制public class UserServiceProxy implements UserService {
private UserService userService = new UserServiceImpl();
@Override
public boolean login(String username, String password) {
System.out.println("开启事务");
boolean result = userService.login(username,password);
System.out.println("结束事务");
return result;
}
@Override
public void removeUser(Integer id) {
System.out.println("开启事务");
userService.removeUser(id);
System.out.println("结束事务");
}
}
使用者:
代码语言:javascript复制public class UserAction {
private UserService userService = new UserServiceProxy();
public String login(){
userService.login("xiaohei", "123456");
return "success";
}
public String removeUser(){
userService.removeUser(1);
return "success";
}
}
2 Spring动态代理
静态代理的问题:
- 随着额外功能的增多,代理类数量随之增多,不利于管理
- 代理类冗余,存在多个代理类提供相同的功能
解决方案:动态代理
Spring动态代理:无需程序员手动编写代理类,只需要提供额外功能代码,然后由Spring框架自动的为原始类生成有增强功能的代理类。
好处:提高开发效率。
开发步骤:
额外引入以下2个依赖:spring-aop aspectjweaver
代码语言:javascript复制<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.26.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
代码语言:javascript复制创建原始类型对象
<bean id="标识" class="原始(目标)类全类名"></bean>
代码语言:javascript复制定义额外功能。实现Spring的特定接口
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
/*
method: 原始类型中方法
args: 参数
target: 原始对象
*/
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before...");
}
}
代码语言:javascript复制配置额外功能类
<!-- 配置功能增强类 -->
<bean id="myBeforeAdvice" class="com.bcl.advice.MyMethodBeforeAdvice"/>
- 定义切入点:决定额外功能添加到哪个位置
组装
<aop:config>
<!-- 定义切入点-->
<aop:pointcut id="myPointCut" expression="execution(* com.bcl.service.*.*(..))"/>
<!-- 组装 -->
<aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="myPointCut"/>
</aop:config>
名词(术语)解释:
- 原始类(目标类):提供核心功能的类
- 原始方法(目标方法):原始类中没有加入额外功能的方法
- 额外功能(增强):用于增强原始方法的代码
3 Spring动态代理的实现流程
4 增强(Advice)
4.1 前置增强
增强会在目标方法前执行,实现接口 MethodBeforeAdvice
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
/*
method: 原始方法
args: 调用方法时的实参列表
target: 原始对象
*/
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("method = [" method "], args = [" Arrays.toString(args) "], target = [" target "]");
System.out.println("target.getClass() = " target.getClass());
System.out.println("前置增强");
}
}
4.2 后置增强
增强代码会在目标方法正常return后执行,实现接口 AfterReturningAdvice
public class MyAfterReturningAdvice implements AfterReturningAdvice {
/*
returnValue: 原始方法正常结束后的返回值
method: 原始方法
args: 实参列表
target: 原始对象
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置增强");
}
}
4.3 异常增强
增强代码在目标方法发生异常时执行,实现接口 ThrowsAdvice
public class MyThrowsAdvice implements ThrowsAdvice {
/*
method: 原始方法
args: 实参列表
target: 原始对象
throwable: 原始方法运行时的异常
*/
public void afterThrowing(Method method, Object[] args,Object target, Throwable throwable){
System.out.println("异常增强");
}
}
4.4 环绕增强
增强代码在目标方法前后以及异常时都可以执行,实现接口 MethodInterceptor
public class MyRoundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation pj) throws Throwable {
System.out.println("前置增强");
Object result = null;
try {
//放行:调用原始方法
result = pj.proceed();
System.out.println("后置增强");
}catch(Exception e){
System.out.println("异常增强");
throw e;
}finally{
System.out.println("最终增强");
}
return result;
}
}
5 切入点详解
切入点:需要做功能增强处理的位置,可以通过切入点表达式描述。
5.1 execution表达式[重点]
实战中,使用 execution(* com.bcl.service.*.*(..))
添加额外功能。
5.2 args表达式
用来匹配特定参数的方法。
args(参数列表)
5.3 within表达式
用来匹配特定的类,根据类名匹配。
within(类名表达式)
5.4 @annotation表达式
@annotation(注解类型),通过特定的注解来匹配类。
代码语言:javascript复制自定义一个注解
public @interface MyAnnotation {
}
代码语言:javascript复制使用自定义注解描述方法(实现类中的方法)
public class UserServiceImpl implements UserService {
@Override
@MyAnnotation
public boolean login(String username, String password) {
System.out.println("username = [" username "], password = [" password "]");
return false;
}
@Override
public void removeUser(Integer id) {
System.out.println("id = [" id "]");
//int i = 10/0;
}
}
代码语言:javascript复制切入点配置为 @annotation(自定义注解类型)
<aop:pointcut id="myPointCut" expression="@annotation(com.bcl.annotation.MyAnnotation)"/>
5.5 表达式的运算符
表达式之间可用过 and or not运算。
6 Spring AOP
AOP(Aspect Oriented Programming)面向切面编程。
OOP(Object Oriented Programming)面向对象编程。
6.1 OOP(面向对象编程)
面向对象编程以对象为单位进行编程,抽取共性方法,通过继承重用这些方法。
6.2 Spring AOP
AOP为了解决程序中零散的共性代码的复用问题,是OOP有力补充。
- 增强:共性代码,额外功能。比如:事务、性能分析
- 切入点:添加额外功能的方法的位置
- 织入(编织):将增强添加到切入点的过程
- 切面:在切点织入增强代码后形成的一个几何平面的概念
面向切面编程的要素:增强、切点和织入
面向切面编程的作用:灵活的以非侵入的方式(非耦合式)为现有的方法增强功能。
Spring切面编程的步骤:
- 配置原始类型对象
- 定义额外功能(增强)
- 配置增强类
- 定义切入点
- 编织
7 数据库中事务的隔离级别
事务的隔离级别:事务并发执行时,微观上多个执行时间相近的事务相互影响的问题。
标准的隔离级别4种:
隔离级别 | 特点 | 问题 |
---|---|---|
READ_UNCOMMITTED | 可以读取到未提交的事务 | 脏读 |
READ_COMMITTED | 只能读到已经提交的事务 | 不可重复读 |
REPEATABLE_READ | 同1个事务中读取到数据始终一致 | 幻影读 |
SERIALIZABLE | 序列化读,不允许并发操作 | 性能差 |
Oracle数据库,只支持2种:READ——COMMITTED
和 SERIALIZABLE
,MySQL支持4种。
MySQL隔离级别的演示:
- 确认MySQL的存储引擎
show engines;
- 查看隔离级别
select @@session.tx_isolation;
- 设置隔离级别
set @@session.tx_isolation=0 | 1 | 2 | 3
- 开启事务
begin;
- 结束事务
commit;
rollback;