• AOP编程简介及其在Spring框架中的使用


    aop编程:
    AOP与OOP互为补充,面向对象编程(OOP)将程序分解成各个层次的对象;面向切面编程(AOP)则是将程序运行过程中分解成各个切面。可以说OOP是从静态角度考虑程序结构而AOP是从动态角度考虑的。

    AOP并不与某个具体类耦合。具有两个特性:1.各步骤之间具有良好的隔离性2.源代码无关性。
    AOP的一些术语:
    1.切面(aspect):切面用于组织多个advice,advice在切面中定义。
    2.连接点(joinpoint):程序执行过程中明确的点,在spring中,连接点总是方法的调用。
    3.增强处理(advice):AOP框架在特定切入点执行增强处理。
    4.切入点(pointcut):可以插入增强处理的连接点。


    OK!接下来代码演示吧,实例永远比空洞的知识强。

    本实例是使用基于注解的方式,另外还有基于xml的。
    先把实例必须的两个javabean贴出

    package Before;
    //定义一个hello接口
    public interface Hello {
    //hello的两个方法
    	public void foo();
    	public int addUser(String name ,String pass);
    }
    
    
    package Before;
    
    import org.springframework.stereotype.Component;
    //注解component指定此为id为hello的bean
    //实现接口并实现方法
    @Component("hello")
    public class HelloImpl implements Hello {
    
    	@Override
    	public void foo() {
    		System.out.println("执行hello主键的foo方法");
    	}
    
    	@Override
    	public int addUser(String name,String pass) {
    		System.out.println("执行hello组键的adduser组键"+name);
    		return 20;
    	}
    
    }
    

    一.定义before增强处理
    定义一个切面,定义一个before增强处理:

    package Before;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    //定义一个切面
    @Aspect
    public class AuthAspect {
    
    	//所有方法的执行作为切入点
    	//括号中的是切入点表达式,文章最后进行介绍
    	@Before("execution(* Before.*.*(..))")
    	public void authority(){
    		System.out.println("模拟进行权限检查");
    	}
    }
    
    

    以下是spring配置文件:

    <!--beans.xml spring的配置文件 -->
    <?xml version="1.0" encoding="UTF-8"?>
    <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 
    	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    	http://www.springframework.org/schema/context
    	http://www.springframework.org/schema/context/spring-context-4.0.xsd
    	http://www.springframework.org/schema/aop
    	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    	<!-- 自动搜索Bean组件 自动搜索切面类 -->
    	<context:component-scan base-package="Before">
    		<context:include-filter type="annotation"
    			expression="org.aspectj.lang.annotation.Aspect"/>
    	</context:component-scan>
    	<!-- 启动@AspectJ支持 -->
    	<aop:aspectj-autoproxy/>
    </beans>
    

    ok,接下来我们来写一个测试类

    package Before;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class AspectTest {
    	public static void main(String[] args) {
    				// 创建Spring容器
    				ApplicationContext ctx = new
    					ClassPathXmlApplicationContext("beans.xml");
    				Hello hello = ctx.getBean("hello" , Hello.class);
    				hello.foo();
    				hello.addUser("孙悟空" , "7788");
    	}
    }
    
    

    上面的所有步骤全部搞定,运行,结果如下
    这里写图片描述
    对比我们不进行AOP处理的结果:
    这里写图片描述
    结果很明显,这就是aop的作用,在不改动源代码的基础上,对源代码进行增强处理。


    2.AfterReturning增强处理
    AfterReturning有的属性值指定形参名,回限制目标方法必须有符合这两个形参。
    不多说,贴代码

    package AfterReturning;
    
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Aspect;
    
    @Aspect
    public class LogAspect {
    	@AfterReturning(returning="rvt", pointcut="execution(* Before.*.*(..)) && args(pass,name)")
    	//声明rvt时指定的类型会限制目标方法必须有返回值或者没有返回值
    	public void log(Object rvt,String pass,String name){
    		System.out.println("第一个参数"+pass);
    		System.out.println("第二个参数"+name);
    		System.out.println("获取目标方法的返回值"+rvt);
    		System.out.println("模拟记录日志功能。。。");
    	}
    }
    
    

    结果(此结果加上before处理后的结果):
    这里写图片描述
    看出差别了吧。


    Afterthrowing增强处理

    package AfterThrowing;
    
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    
    @Aspect
    public class RepairAspect {
    
    	@AfterThrowing(throwing="ex",pointcut="execution(* Before.*.*(..))")
    	public void doRecoveryActions11(Throwable ex){
    		System.out.println("目标方法抛出的异常"+ex);
    		System.out.println("模拟advice对异常的修复....");
    	}
    }
    
    

    该写一下前面的helloimpl类

    package Before;
    
    import org.springframework.stereotype.Component;
    
    @Component("hello")
    public class HelloImpl implements Hello {
    
    	@Override
    	public void foo() {
    		System.out.println("执行hello主键的foo方法");
    	}
    
    	@Override
    	public int addUser(String name,String pass) {
    		System.out.println("执行hello组键的adduser组键"+name);
    		if(name.length()<=3||name.length()>=10){
    			throw new IllegalArgumentException("name的参数必须大于3小于10");
    		}
    		return 20;
    	}
    
    }
    

    在xml文件中加入切面类所在的包,结果如下
    这里写图片描述
    可以看出,增强处理起作用了。


    时间问题,after增强处理就不讲了,很简单,跟before差不多,只不过一个在目标方法之前,一个在后。


    Around增强处理

    贴代码,两点多了,有点困了,

    package Around;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    @Aspect
    public class TxAspect{
    
    	@Around("execution(* Before.*.*(..))")
    	public Object processTx (ProceedingJoinPoint jp) throws Throwable{
    		System.out.println("执行目标方法之前,模拟开始事务.....");
    		//获取目方法原始的调用参数
    		Object [] args=jp.getArgs();
    		if(args!=null&&args.length>1){
    			//修改目标方法调用参数的第一个参数
    			args[0] ="【增加的前缀】"+args[0];
    		}
    		//以改变后的参数去执行目标方法,并保存目标方法返回的执行值
    		Object rvt=jp.proceed(args);
    		System.out.println("模拟事务结束........");
    		if(rvt!=null&&rvt instanceof Integer){
    			rvt=(Integer)rvt*(Integer)rvt;
    		}
    		return rvt;
    	}
    }
    
    

    额,这个相对有点复杂,该类的方法processTx有个参数,就是代表目标方法,执行第一个输出之后,必须重新调用这个目标方法让他执行完再执第二个输出。

    配置xml,后执行测试类
    这里写图片描述

    看到结果。和程序中描述的一样。


    注: execution(* Before..(..)) && args(pass,name)
    第一个*表示目标方法的返回值任意。
    第二个 第三个表示 任意类的任意方法
    &&后面的表示对连接点的参数类型进行限制,可以过滤目标方法。


    关注笔者公众号,推送各类原创/优质技术文章 ⬇️

  • 相关阅读:
    拓端tecdat|R语言投资组合优化求解器:条件约束最优化、非线性规划求解
    拓端tecdat|R语言多元时间序列滚动预测:ARIMA、回归、ARIMAX模型分析
    拓端tecdat|R语言聚类有效性:确定最优聚类数分析IRIS鸢尾花数据和可视化
    拓端tecdat|R语言k-means聚类、层次聚类、主成分(PCA)降维及可视化分析鸢尾花iris数据集
    【拓端tecdat】R语言用Hessian-free 、Nelder-Mead优化方法对数据进行参数估计
    springcloud之zuul网关服务并携带头信息转发token
    windows环境搭建Vue开发环境
    JVM之top+jstack分析cpu过高原因
    JVM调优之jstack找出最耗cpu的线程并定位代码
    用自顶向下、逐步细化的方法进行以下算法的设计: 1. 输出1900---2000年中是软黏的年份,符合下面两个条件之一的年份是闰年:
  • 原文地址:https://www.cnblogs.com/dongxishaonian/p/12666603.html
Copyright © 2020-2023  润新知