SpringAop原理

SpringAop原理

  • SpringAop前身
    • 先前的动态代理,定义代理类
    • Aop的Aspect注解

SpringAop前身

Aop:: 面向切面编程 在不影响核心代码的前提下,可以在任意位置添加非核心代码。
AOP基于IOC基础,是对OOP的有益补充。
通过动态代理实现核心业务和非核心业务的一种抽取。比较麻烦。 可以使用spring 的aop来完成代理
AOP常用的术语有:通知、切点、和连接点
通知(Advice):定义了切面是什么以及何时使用
Spring有5种通知类型:
Before——前置通知:在方法调用之前调用通知
After——返回通知:在方法完成之后调用通知,无论方法是否执行成功;
After-returing——正常返回通知:在方法成功执行之后调用;
After-throwing——异常返回通知:在方法抛出异常时调用通知;
Around——环绕通知:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

连接点(Joinpoint):是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时(程序中的任意地方)。
切点(pointcut):一个切面并不需要通知应用的所有连接点。切点有助于缩小切面所通知连接点的范围。通常使用明确的类和方法来定义这些切点,或是利用正则表达式定义匹配的类和方法名称模式来指定这些切点。对比:连接点相当于数据库中的记录,切点相当于查询条件
切面(Aspect):通知和切点的结合,通知和切点共同定义了关于切面的全部内容——它是什么,在何时和何处完成其功能。被模块化的特殊对象。如日志类。

先前的动态代理,定义代理类

public class MyProxy {
    //    目标对象
    private ArithmeticCalculator target;

    //构造函数
    public MyProxy(ArithmeticCalculator a) {
        this.target = a;
    }

    //jdk子代的原生动态代理   必须基于接口
//    ClassLoader loader,被代理对象的加载器
//        Class[] interfaces, 被代理对象实现的借口
//        InvocationHandler h: 被代理对象那些相位需要被代理
    public ArithmeticCalculator getProxyInstance() {
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = {ArithmeticCalculator.class};
        InvocationHandler h = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("BBB"+method.getName()+ Arrays.asList(args));
                Object result = method.invoke(target, args);

                return result;
            }
        };
        return (ArithmeticCalculator) Proxy.newProxyInstance(classLoader, interfaces, h);
    }

Aop的Aspect注解

(1)把相关spring的依赖加入

 <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.2.9.RELEASEversion>
        dependency>

        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-jdbcartifactId>
            <version>5.2.9.RELEASEversion>
        dependency>

        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-aspectsartifactId>
            <version>5.2.9.RELEASEversion>
        dependency>
    dependencies>
(2)创建一个切面类

Aspect支持 5 种类型的通知注解:
@Before: 前置通知, 在方法执行之前执行
@After: 后置通知, 在方法执行之后执行
@AfterRunning: 返回通知, 在方法返回结果之后执行
@AfterThrowing: 异常通知, 在方法抛出异常之后
@Around: 环绕通知, 围绕着方法执行

//日志切面类
@Component
@Aspect//表示该类为切面类   删除某一个记录  添加日志  操作日志 事务  (1)开启事务  (2)提交事务  (3)事务回滚
public class LogAspect {
    //    public  double返回类型
//    表示在这个方法前执行次方法
//    @Before(value = "execution(public double com.zz.proxy.after.ArithmeticCalculatorImpl.add(double,double))")
//    表示com.zz.proxy.after下的所有类,所有的方法,所有的参数
//    前置通知
    @Before(value = "execution(* com.zz.proxy.after.*.*(..))")
    public void before(JoinPoint joinPoint) {
//        得到方法对象
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("AAA--->" + name + "method begin with" + Arrays.asList(args));
    }


    //    后置通知  finally
    @After(value = "execution(* com.zz.proxy.after.*.*(..))")
    public void after(JoinPoint joinPoint) {
//        得到对象的方法
        String name = joinPoint.getSignature().getDeclaringType().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("该方法总会被执行");
    }


//  后置返回通知
    @AfterReturning(value = "execution(* com.zz.proxy.after.*.*(..))",returning ="r")
    public void afterReturning(JoinPoint joinPoint,int r){
        String name = joinPoint.getSignature().getName();
        System.out.println("AAA---> The "+name+" method ends:"+r);

    }

//    有return先执行afterReturning 在执行after
//    异常就直接走


//相当于catch  只有发生异常时才会执行
    @AfterThrowing(value = "execution(* com.zz.proxy.after.*.*(..))",throwing = "e")
    public void afterThrowing(Exception e){
//        打印异常信息
        System.out.println(e.getMessage());
    }

(3) 配置文件开启切面注解


<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:mvc="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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    
    <context:component-scan base-package="com.ykq.aop.after"/>

    
    <mvc:aspectj-autoproxy />
beans>

(4) 测试

 ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        ArithmeticCalculator contextBean = (ArithmeticCalculator) context.getBean("arithmeticCalculatorImpl");
//        Double add = contextBean.add(10, 2);
        int add = contextBean.sub(10, 2);
        System.out.println(add);
//        System.out.println(10/0);

你可能感兴趣的:(spring,aop,java,mybatis)