Spring 学习很瘦身2

AOP 面向切面编程

AOP(aspect-oriented-programming)确保 POJO 的简单性以及核心业务的内聚性,借助 AOP 可以将安全、事务和日志关注点与核心业务逻辑相分离。

1. 1 实现方式

  • 预编译
    • AspectJ
  • 运行期动态代理(JDK 动态代理、CGLib 动态代理)
    • SpringAOP、JbossAOP

1.2 Spring中的作用

  • 提供声明式的企业服务,特别是 EJB 的替代服务声明
  • 允许自定义方面,互补 OOP(面向对象) 与 AOP(面向切面)的使用

1.3 Spring中的实现

  • 接口/接口集默认 JavaSE 动态代理作为 AOP 的代理标准
  • 无接口可使用 GCGLIB 的代理实现

二、AOP 概念介绍

2.1 aspect 切面

<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
    <!-- 切面类 -->
    <bean id="AspectBean_id" class=[AspectBeanPath]/>   
    <!-- 业务类 -->
    <bean id="BizBean_id" class=[BizBeanPath]/>

    <aop:config>
        <aop:aspect id="AspectBeanAOP_id" ref="AspectBean_id"/>
    </aop:config>
<beans>

2.2 pointcut 切入点

2.2.1 切入方法

functionimpact
execution匹配方法执行的连接点
within/@within限定匹配指定类型的连接点
this匹配特定连接点的 bean,引用柿子顶类型实例的限制
target/@target限定匹配当特定连接点的代理对象,对象是指定类型的实例
args/@args限定匹配特定连接点实际传入参数的类型实例
@annotation限定匹配指定连接点的主体

2.2.2 切入类型

examplepointcut
excution(public * *(..))所有 public 执行方法
excution(* set*(..))所有 set 开始的方法
excution(* com.example.bean.AClazz.*(..))AClazz 类中所有方法
excution(* com.example.bean..(..))com.example.bean 包下所有方法
excution(* com.example.bean…(..))com.example.bean 包即包下所有方法

2.2.3 切入示例

<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
    <!-- 切面类 -->
    <bean id="AspectBean_id" class=[AspectBeanPath]/>   
    <!-- 业务类 -->
    <bean id="BizBean_id" class=[BizBeanPath]/>

    <aop:config>
        <aop:aspect id="AspectBeanAOP_id" ref="AspectBean_id">
            <aop:pointcut expression="excution(public * *(..))" id=[POINTCUT_ID]/>
        </aop:aspect> 
    </aop:config>
<beans>

2.2.4 切入组合

表达式可通过 &&、|| 或者 ! 进行组合,亦可通过名字引用切入点表达式,如下:

@Pointcut("excution(...)")
private void aFunction(){}

@Pointcut("excution(...)")
private void bFunction(){}

@Pointcut("aFunction() && bFunction()")
private void cFunction(){}

2.2.5 切入规范

  • 选择特定类型的连接点,如:execution,get,set,call,handler
  • 确定连接点范围,如:within,withincode
  • 匹配上下文信息,入:this,target,@annotation

2.3 Advice 通知

2.3.1 使用实例

<aop:aspect id="AspectBeanAOP_id" ref="AspectBean_id">
    <aop:pointcut expression="excution(public * *(..))" id=[POINTCUT_ID]/>
    <!-- 执行时前置通知 -->
    <aop:before method = [AspectBean_DO_FUNCTION] pointcut-ref=[POINTCUT_ID]/>
    <!-- 返回时,受已成影响 -->
    <aop:after-returning method = [AspectBean_DO_FUNCTION] pointcut-ref=[POINTCUT_ID]/>
    <!-- 异常时 -->
    <aop:after-throwing method = [AspectBean_DO_FUNCTION] pointcut-ref=[POINTCUT_ID]/>
    <!-- 执行完后置通知,不受异常影响 -->
    <aop:after method = [AspectBean_DO_FUNCTION] pointcut-ref=[POINTCUT_ID]/>
    <!-- 同上不受异常干扰,多用于资源的释放 -->
    <aop:finally method = [AspectBean_DO_FUNCTION] pointcut-ref=[POINTCUT_ID]/>
    <!-- 环绕执行,即执行前于执行后。位于通知方法首个参数必需为 ProceedingJoinPoint 类型 -->
    <aop:aspect method = [AspectBean_DO_FUNCTION] pointcut-ref=[POINTCUT_ID]/>
</aop:aspect> 

或通过代码实现:

@Component
@Aspect
public class MoocAspect {

    @Before("execution(...)")
    public void befor() {}

    @After("execution(...)")
    public void after() {
        // after、finally 的实现
    }

    @AfterReturning(pointcut="execution(...)", returning="returnValue")
    public void afterReturning(Object returnValue) {
        // retrunValue 具体返回值,类型可依据实际情况确认    
    }

    @AfterThrowing(pointcut="execution(...)", throwing="e")
    public void afterThrowing(Exception e) {
        // e 具体异常类型信息,异常可依据实际情况确认   
    }

    @Around("execution(...)")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        // 此处执行于方法前
        Object obj = pjp.proceed();// 真正执行的行为,obj 可能为 null
        // 此处执行于方法后
        return obj;
    }
}

2.3.2 使用扩展

  • 参数
@Component
@Aspect
public class MoocAspect {

    @Before("execution(...) && args(arg)")
    public void beforeWithParam(String arg) {
        // arg 获取传入参数值
    }

    @Before("execution(...) && @annotation(moocMethod)")
    public void beforeWithAnnotaion(MoocMethod moocMethod) {
        // moocMethod 获取传入注解内容
    }

    @Before("execution(...) && args(arg) && @annotation(moocMethod)",
        argName="arg, moocMethod")
    public void beforeWithArgNames(String arg, MoocMethod moocMethod) {
        // 指定注解方法的参数名
        // JoinPoint,ProceedingJoinPoint,JoinPoint.StraticPart 可忽略
    }
}
  • 泛型
public interface Sample<T>{
    void sampleGenericMethod(T param);
    void sampleGenericCollectionMethod(Coolection<T> param);
}
@Component
@Aspect
public class MoocAspect {

    @Before("execution(..Sample.sampleGenericMethod(*)) && args(arg)")
    public void beforeWithParam(String arg) {
        // arg 指定泛型类型为 String
    }

    @Before("execution(..Sample.sampleGenericCollectionMethod(*)) && args(arg)")
    public void beforeWithParam(Collection<String> arg) {
        // arg 指定泛型集合类型为 String
    }
}

2.4 Introduction 引入

允许一个切面声明一个实现指定接口的通知对象,并提供了一个接口实现类来代表这些对象。实现方式:

  • 在 < aop:aspect > 声明 < aop:declare-parents > 匹配新的 parent
<aop:config>
    <aop:aspect id="" ref="">
        <aop:declare-parents
            <!-- 指定接口对象 -->
            implement-interface=""
            <!-- 接口实现,代表以上对象 -->
            defalult-impl=""/>
    </aop:aspect>
</aop:config>
  • 代码中使用 @DeclareParents 进行注解,且用来匹配拥有新的 parent
public interface Sample{
    void sampleMethod();
}
@Aspect
public class IntroductionAspect {

    @DeclareParents(value="execution(...)", defaultImpl=Sample.class)
    public static Sample sample;

    @Before("execution(...) && this(sample2)")
    public void recordIntroduction(Sample sample2) {
        sample2.sampleMethod();
    }
}

2.5 Advisors

  • 仅有一个 advice , 切面自身通过一个 bean 表示并实现相应的 advice 接口;

2.6 AOP Proxy 代理

2.6.1 Target Object 目标对象

  • 默认 CGLIB 代理
  • 实际通过 ProxyFatoryBean 对象的 getObject() 函数获取到代理对象
  • 配置文件当中通过 < proerty name=”target”> 声明代理对象
  • 继承接口 MethodInterceptor 可实现 *通配符设定

2.6.2 Proxy 的定义

<bean id="" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target"><bean ...></property>
    <property name="interceptorNames"><list><value>...</list></property>
</bean>  

可通过以下方式,简化以上定义:

<bean id="baseProxyBean" class="org.springframework.aop.framework.ProxyFactoryBean" 
            lazy-init="true" abstract="true"></bean>
<bean id="" parent="baseProxyBean">
    <property name="target"><bean ...></property>
    <property name="interceptorNames"><list><value>...</list></property>
</bean>  

通过以下方式,实现自动代理 auto-proxy

<bean id="" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames" value=[通配符定义]/>
    <property name="interceptorNames"><list><value>...</list></property>
</bean>  

同样的,可以通过以下方式简化以上自动代理(暂为理解,后继完善)

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

AOP API 的使用

apimethodimpact
BeforeAdvicevoid before(Method m, Object[] args, Object target)连接点插入前执行
ThrowsAdvicevoid afterThrowing([Method, args, target], ThrowableSubclass)连接点返回后执行
AfterReturningAdvicevoid afterReturning(Object returnValue, Method m, Object[] args, Object target)后置通知必需实现
InterceptorObject invoke(MethodInvocation invocaton)针对不同的 advice 启用相同的切入点
IntroductionInterceptorboolean implementsInterface(Class intf)
IntroductionAdvisorvoid validateInterfaces()
IntroductionInfoClass[] getInterfaces()
Lockablevoid lock()
void unlock()
boolean locaked()
Object invoke(MethodInvocation invocation)
锁住
解锁
锁状态
根据锁状态的操作
DefaultIntroductionAdvisorLockMixinAdvisor()持独立 LockMixin 实例的构造函数

注解 @AspectJ

注解类型描述
@Commponent声明可以被 bean 容器识别
@Aspect 切面1.注解 bean 将被 Spring 自动识别并应用
2.可包括切入点 pointcut,通知 Advice 和引入 introduction 的声明
3.需配合 @Component 注释或 xml 配置
@Pointcut 切入点方法返回类型必需是 void

切面实例化模型

在对象执行并创建切面实例后跟随对象的失效而失效(fk:有句麻卖批不知当讲不当讲,不管先记录下再说),以下为具体实现

@Aspect("perthis(execution(...))")
public class MyAspect {}

Spring 学习很瘦身1
Spring 学习很瘦身2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值