Spring-AOP

Spring-AOP

Aspect Oriented Programing:面向切面编程

相对oop(面向对象)来说,aop关注的不再是某个类,而是层与层之间的切入

AOP主要在日志记录,性能统计,安全控制,事务控制等方面实现公共功能的复用

AOP降低模块之间的耦合度,提高业务代码的聚合

提高代码的复用

保持系统的扩展性

AOP基本概念

Joinpoint(连接点)

指在切入点中拦截到的所有方法,一个连接点即代表一个方法的执行

Pointcut(切入点)

对连接点拦截的定义,即定义拦截某些或某种方法

Advice(通知)

拦截连接点后所作的操作

​ 前置通知 before():在执行方法前执行的通知

​ 异常通知 afterThrow():在方法出现异常 时执行的通知

​ 最终通知 after():不管方法是否异常都会执行的通知

​ 返回通知 afterReturn():方法正常结束后执行的通知

​ 环绕通知 around():将前四种方法集中在一个方法中,可以自由定义执行哪些通知,是唯一具有返回值的方法,也是最强大的一种通知类型

Aspect(切面)

为poincut与advice的结合,poincut定义拦截的方法,advice定义拦截方法的后续操作,而Aspect则是对横切面的整体抽象

Target(目标对象)

即被代理的对象

Weave(织入)

将切面引用到目标对象并生成代理对象的过程

Introduction(引入)

在不修改原有应用程序代码的情况下,在程序运行期为类动态添加方法或者字段的过程

AOP 注解实现(推荐使用)

<!--spring AOP实现需要引入的jar包-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
</dependency>

<!-- 配置spring环境 -->
<?xml version="1.0" encoding="UTF-8"?>

<!--
	spring-AOP配置
        xmlns:aop="http://www.springframework.org/schema/aop"
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
-->

<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
        https://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">

    <!-- 配置扫描包范围路径 -->
    <context:component-scan base-package="com.lysxd"/>

    <!-- 开启aop环境 -->
    <aop:aspectj-autoproxy/>

</beans>
/*
	定义目标类
*/

@Component
public class Target01{
    public void targetTest(){
        System.out.println("TargetTest...");
    }
}
//定义Aspect

@Compoent
//标识为AOP
@Aspect
public class TestAspect{
    /*
    	定义pointcut 
    	使用execution执行匹配 
    	* com.lysxd.annotation..*.*(..)
    	
    	* 指被所有修饰符修饰的类(public|private|protected)
    	com.lysxd.annotation 指切入点指定的包
    	* com.lysxd.annotation.*.*(..) 指在com.lysxd.annotation包下的所有子类的方法(*可改为指定类和方法)
    	* com.lysxd.annotation..*.*(..)指在com.lysxd.annotation包及子包下的所有子类的方法(*可改为指定类和方法)
    	
    */
    @Pointcut("execution(* com.lysxd.annotation..*.*(..))")
    public void cut(){};
	
    //定义前置通知且引入pointcut
    @Before(value="cut()")
    public void before(){
        System.out.println("前置通知:在目标方法执行之前执行的方法");
    }
    
    //定义异常通知
    @AfterThrowing(value="cut()")
    public void afterThrowing(){
        System.out.println("异常通知:在目标方法执行发生异常时执行的方法");
    }
    
    //定义最终通知
    @After(value="cut()")
    public void after(){
        System.out.println("最终通知:不管目标方法时候异常都会执行的方法");
    }
    
    //定义返回通知
    @AfterReturning(value="cut()")
    public void afterReturning(){
        System.out.println("返回通知:在目标方法正常结束时执行的方法");
    }
    
    //定义环绕通知
    @Around(value="cut()")
    public Object around(ProceedingJinPoint psj)throws Throwable{
        Object result = null;
        System.out.println("环绕方法开始执行");
        System.out.println("方法开始时间为:"+System.currentTimeMillis());
        //可以获取方法的形参,为数组
        Object[] args = psj.getArgs();
        if(null!=args && args.length>0){
            for(Object arg:args){
                System.out.println("方法的形参为:"+arg);
            }
        }
        
        //执行目标方法
        result = psj.proceed();
        System.out.println("方法结束时间为:"+System.currentTimeMillis());
        return result;
    }
    
}
/*
	切面测试
*/
public class Test(){
    @Test
    public void test01(){
        //根据配置文件构建IOC容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring-annotation.xml");
    }
    //配置目标类时系统自动将首字母配置为小写
    Target01 target01 = (Target01)ac.getBean("target01");
    //调用目标方法
    target01.targetTest();
}
/*
	将特定注解标识的类定义为切面
	使用@annotation 执行匹配
*/

//定义注解
@Target(METHOD) //注解可用在方法上 
@Retention(RUNTIME) //在类执行时保留
public @interface AnnotationPointCut{
    //可以定义注解的value,default为空
    String value() default "";
}

//定义连接点
@AnnotationPointCut(value = "test02")
public void test02(){
    System.out.println("test02...");
}
@AnnotationPointCut(value = "test03")
public void test03(){
    System.out.println("test03...");
}
//匹配注解的方法
@Pointcut("@annotation (com.lysxd.annotation.AnnotationPointCut)")
public void annotationCut(){};

//定义环绕方法
@Around(value = "annotationCut()")
public Object Around(ProceedingJoinPoint psj)throws Throwable(){
    Object result = null;
    System.out.println("环绕方法开始执行");
    System.out.println("方法开始时间为:"+System.currentTimeMillis());
    //执行目标方法
    result = psj.proceed();
    System.out.println("方法结束时间为:"+System.currentTimeMillis());
    return result;
}
/*
	可以指定特质value的AnnotationPointCut注解
*/
//定义环绕方法
@Around(value = "annotationCut()")
public Object Around(ProceedingJoinPoint psj)throws Throwable(){
    Object result = null;
   
    /*
    	获取指定value注解标识的方法
    		获取方法签名
    		根据方法签名获取方法,继而获取当前方法的注解
    		获取当前方法注解的值
    */
    MethodSingnature methodSingtrue = (MethodSingnature) psj.getSingtrue();
    AnnotationPointCut annotationPointCut = methodSingtrue.getMethod().getAnnotation(AnnotationPointCut.calss);
    if(null != annotationPointCut){
        //当注解的value为test02时
        if("test02".equals(annotationPointCut.getvalue())){
            System.out.println("注解value为test02的连接点");
        }
        if("test03".equals(annotationPointCut.getvalue())){
            System.out.println("注解value为test03的连接点");
        }
    }
    //执行目标方法
    result = psj.proceed();
    return result;
}

AOP 配置XML实现

AOP-XML配置方式中各类方法的顺序会受到配置文件中的配置顺序的影响

<!--spring AOP实现需要引入的jar包-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
</dependency>
<!-- 配置spring环境 -->
<?xml version="1.0" encoding="UTF-8"?>

<!--
	spring-AOP配置
        xmlns:aop="http://www.springframework.org/schema/aop"
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
-->

<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
        https://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">

    <!-- 配置扫描包范围路径 -->
    <context:component-scan base-package="com.lysxd"/>

    <!-- 开启aop环境 -->
    <aop:aspectj-autoproxy/>
    
    <!-- 配置aop -->
    <aop:config>
    	<!-- 配置Aspect -->
        <aop:aspect ref="TestAspect02" />
        	<!-- 配置pointcut -->
        	<aop:pointcut id="lysxd" expression="execution (* com.lysxd.aopxml)" />
            <!-- 定义前置通知 method:方法名 pointcut-ref:引用定义的切入点 -->
        	<aop:before method="before" pointcut-ref="lysxd" />
        	<!-- 定义异常通知 -->
        	<aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="lysxd" />
        	<!-- 定义最终通知 -->
        	<aop:after method="after" pointcut-ref="lysxd" />
        	<!-- 定义返回通知 -->
        	<aop:after-returning method="afterReturning" pointcut-ref="lysxd" />
        	<!-- 定义环绕通知 -->
            <aop:around method="around" pointcut-ref="lysxd" />
        </aop:aspect>
    </aop:config>

</beans>
/*
	定义Aspect
*/
@Component
@Aspect
public class LoginAopXML {

    public void before(){
        System.out.println("前置通知-->目标类方法执行前执行的方法");
    }

    public void after(){
        System.out.println("最终通知-->目标类是否异常都会执行的方法");
    }

    public void afterThrowing(Exception e){
        System.out.println("异常通知-->目标类出现异常时执行的方法,当此方法执行后整个方法结束"+e);
    }

    public void afterReturning(){
        System.out.println("返回通知-->目标类方法执行结束后执行的方法");
    }

    public Object around(ProceedingJoinPoint psj) throws Throwable {

        Object result = null;
        System.out.println("环绕方法开始执行");
        Long startTime = System.currentTimeMillis();
        System.out.println("方法开始时间为:"+startTime);

        //获取方法的形参
        Object[] args = psj.getArgs();
        //当数组非空时kkj\8遍历方法的形参
        if(null != args && args.length > 0){
            for (Object arg : args) {
                System.out.println("方法形参-->"+arg);
            }
        }

        //执行目标方法
        result = psj.proceed();

        Long endTime = System.currentTimeMillis();
        System.out.println("方法结束时间为:"+startTime);
        return result;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值