一、装饰模式
装饰设计模式:在不必改变源代码基础上,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是包裹真实的对象。就是对已有对象进行功能的增强。
静态代理:
在程序运行前就已经存在代理类的字节码文件,代理对象和真实对象的关系在程序运行前就确定了。
动态代理:
动态代理类是在程序运行期间由JVM通过反射等机制动态的生成的,所以不存在代理类的字节码文件。代理对象和真实对象的关系是在程序运行时期才确定的。
静态代理优缺点:
优点:业务类只需要关注业务逻辑本身,保证了业务类的重要性。
缺点:
- 代理对象的某个接口只服务于某一种类型的对象,也就是说每一个真实对象都得创建一个代理对象
- 如果需要代理的方法很多,则要为每一种方法都进行代理处理
- 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度
二、AOP概念
1、AOP:Aspect oritention programming(面向切面编程)
2、AOP的目的:
AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
3、AOP的优势:
降低模块的耦合度、使系统容易扩展、更好的代码复用性
4、Spring的AOP使用动态代理实现:
- 如果一个类实现了接口,那么spring就使用JDK的动态代理完成AOP;
- 如果一个类没有实现接口,那么spring就是用cglib完成AOP;
5、AOP当中的概念:
- 5.1、切入点(Pointcut):在哪些类,哪些方法上切入(where);
- 5.2、增强(Advice):早期翻译为通知,在方法执行的什么时机(when:方法前/方法后/方法前后)做什么(what:增强的功能);
- 5.3、切面(Aspect):切面=切入点+通知,通俗点就是:什么时机,什么地点,做什么!
- 5.4、织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)。
三、XML配置AOP
1、jar包
- spring-aop-5.1.0.RELEASE.jar
- com.springsource.org.aopalliance-1.0.0.jar
- com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
2、表示在哪些方法上增强——AspectJ(语言)
- AspectJ切入点语法如下
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?
name-pattern(param-pattern)throws-pattern?)
翻译成中文:
execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)
- 在所有的业务层方法上做增强:
execution (* com.revanwang.pss.service.*Service.*(..))
AspectJ.png
3、配置AOP命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
</beans>
4、配置AOP
<!-- 配置AOP: 1.切面: what 2.切入位置:where 3.切入时机:when -->
<aop:config>
<aop:aspect ref="txManager"><!--what:增强了什么-->
<!--where:哪些包下的哪些类中的哪些方法上增强-->
<aop:pointcut expression="execution(* com._520it.aop.*Service.*(..))" id="txPoint" />
<!--when:在方法的前/后增强-->
<aop:before method="beginTransaction" pointcut-ref="txPoint" />
<aop:after-returning method="commit" pointcut-ref="txPoint"/>
<aop:after-throwing method="rollback" pointcut-ref="txPoint"/>
</aop:aspect>
</aop:config>
四、注解配置AOP
4.1:各种不同的增强:
- aop:before(前置增强):在方法执行之前执行增强;
- aop:after-returning(后置增强):在方法正常执行完成之后执行增强(中间没有遇到任何异常);
- aop:throwing(异常增强):在方法抛出异常退出时执行增强代码;
- aop:after(最终增强):在方法执行之后执行,相当于在finally里面执行;可以通过配置throwing来获得拦截到的异常信息
-
aop:around(环绕增强):最强大的一种增强类型。 环绕增强可以在方法调用前后完成自定义的行为,环绕通知有两个要求,
- 1,方法必须要返回一个Object(返回的结果)
- 2,方法的第一个参数必须是ProceedingJoinPoint(可以继续向下传递的切入点)
Spring_TX.png
4.2:AOP相关的标签解析器
<!-- 扫描包中的bean组件 -->
<context:component-scan base-package=""/>
<!-- AOP的自动代理 -->
<aop:aspectj-autoproxy/>
- @Component("txManager")
- @Aspect//<aop:aspect ref="txManager">:做什么
public class TransactionManager{
//切入点
//<aop:pointcut expression="execution(* com._520it.day2.aop_ann.*Service.*(..))" id="txPoint"/>
@Pointcut("execution(* cn.itsource.day2.aop_ann.*Service.*(..))")
public void txPoint(){}
//前置增强:<aop:before method="beginTransaction" pointcut-ref="txPoint"/>
@Before("txPoint()")
public void beginTransaction(JoinPoint jp) {
System.out.println("开启事务.....");
}
//后置增强:<aop:after-returning method="commit" pointcut-ref="txPoint"/>
@AfterReturning("txPoint()")
public void commit() {
System.out.println("提交事务.....");
}
//异常增强:<aop:after-throwing method="rollback" pointcut-ref="txPoint" throwing="ex"/>
@AfterThrowing(value="txPoint()",throwing="ex")
public void rollback(Throwable ex) {
System.out.println(ex.getMessage());
System.out.println("回滚事务.....");
}
//最终增加:<aop:after method="close" pointcut-ref="txPoint"/>
@After("txPoint()")
public void close() {
System.out.println("关闭session.....");
}
//环绕增强:<aop:around method="around" pointcut-ref="txPoint"/>
@Around("txPoint()")
public Object around(ProceedingJoinPoint pjp) {
System.out.println("开启事务.....");
try {
Object ret = pjp.proceed();//调用正在的业务方法
System.out.println("提交事务.....");
return ret;
} catch (Throwable e) {
System.out.println("回滚事务....."+e.getMessage());
} finally {
System.out.println("关闭session.....");
}
return null;
}
}
建议使用XML配置AOP,通用,可维护性较高。
网友评论