SpringAOP的核心使用

news/2024/7/19 14:30:46 标签: ioc, proxy, spring, java, aop

SpringAOP

AOP:Aspect Oriented Programming,意思为面向切面编程

面向切面编程:对于不同的模块,在具有相同共性的情况下,由切面的增强来负责统一处理;其本质就是动态代理

相对于OOP(面向对象)来说,AOP对于过程的管理更加的精细,能够进一步来完成解耦工作,在程序运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想,将不同的方法的同一个位置抽象成一个切面对象

AOP的特点:

  • 降低模块之间的耦合度。

  • 使系统更容易扩展。

  • 更好的代码复用。

  • 非业务代码更加集中,不分散,便于统一管理。

  • 业务代码更加简洁纯粹,不参杂其他代码的影响。

AOP相关术语:

  • 增强(Advice)
  • 切入点(Pointcut)
  • 连接点(Joinpoint)
  • 切面(Aspect)
  • 代理(Proxy)
  • 目标对象(Target)
  • 织入(Weaving)

动态代理

场景:苹果手机与苹果电脑,华为手机与华为电脑的销售

接口:

java">package com.m.staticproxy;

public interface Phone {
    public String salePhone();
}

java">package com.m.staticproxy;

public interface Computer {
    public String saleComputer();
}

实现类:

java">package com.m.staticproxy.impl;

import com.m.staticproxy.Computer;
import com.m.staticproxy.Phone;

public class Apple implements Phone,Computer {
    @Override
    public String salePhone() {
        return "销售Apple手机";
    }

    @Override
    public String saleComputer() {
        return "销售Apple电脑";
    }
}

java">package com.m.staticproxy.impl;

import com.m.staticproxy.Computer;
import com.m.staticproxy.Phone;

public class HuaWei implements Phone,Computer {
    @Override
    public String salePhone() {
        return "销售HuaWei手机";
    }

    @Override
    public String saleComputer() {
        return "销售HuaWei电脑";
    }
}

MyInvocationHandler类:

java">package com.m.staticproxy.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class MyInvocationHandler implements InvocationHandler {
    private Object proObject;

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Object bind(Object object) {
        this.proObject = object;
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(this.proObject);
        System.out.println(name+"卖的好,这个"+name+"物美价廉,赶快来抢购吧!");
        System.out.println(result);
        System.out.println(method.getName()+"方法的结果是"+result);
        return result;
    }
}

测试类:

java">package com.m.staticproxy;

import com.m.staticproxy.Phone;
import com.m.staticproxy.impl.Apple;
import com.m.staticproxy.impl.HuaWei;
import com.m.staticproxy.proxy.MyInvocationHandler;
import com.m.staticproxy.proxy.PhoneProxy;

public class Test {
    public static void main(String[] args) {
        Phone phone1 = new Apple();

        Phone phone2 = new HuaWei();

        Computer computer1 = new Apple();

        Computer computer2 = new HuaWei();

        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();

        myInvocationHandler.setName(phone1.salePhone().substring(2));
        phone1 = (Phone) myInvocationHandler.bind(phone1);
        phone1.salePhone();

        myInvocationHandler.setName(phone2.salePhone().substring(2));
        phone2 = (Phone) myInvocationHandler.bind(phone2);
        phone2.salePhone();

        myInvocationHandler.setName(computer1.saleComputer().substring(2));
        computer1 = (Computer) myInvocationHandler.bind(computer1);
        computer1.saleComputer();

        myInvocationHandler.setName(computer2.saleComputer().substring(2));
        computer2 = (Computer) myInvocationHandler.bind(computer2);
        computer2.saleComputer();

    }
}

用静态代理得写手机代理类和电脑代理类,动态代理用的是面向对象的多态思想,一个类搞定。

aop_190">Spring-aop

在Spring框架中,我们不需要创建动态代理类,只需要创建一个切面类,由该切面类产生的对象就是切面对象,可以将非业务代码写入到切面对象中,再切入到业务方法中,Spring框架底层会自动根据切面类以及目标类生成一个代理对象。

1.配置pom环境

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.7.RELEASE</version>
  </dependency>
  
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.7.RELEASE</version>
  </dependency>
  
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.3.7.RELEASE</version>
  </dependency>

2.spring-aop.xml

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-4.3.xsd
">

    <!-- 自动扫码 -->
    <context:component-scan base-package="com.m"></context:component-scan>

    <!-- 使Aspect注解生效,为委托类自动生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

目标类需要添加@Component注解

java">package com.m.action_proxy.impl;

import com.m.action_proxy.Cal;
import org.springframework.stereotype.Component;

@Component
public class CalImpl implements Cal {
    @Override
    public int add(int num1, int num2) {
        return num1 + num2;
    }

    @Override
    public int sub(int num1, int num2) {
        return num1 - num2;
    }

    @Override
    public int mul(int num1, int num2) {
        return num1 * num2;
    }

    @Override
    public int div(int num1, int num2) {
        return num1 / num2;
    }
}

LoggerAspect类定义处添加了两个注解:

  • @Aspect:表示该类是切面类。
  • @Component:将该类注入到IoC容器中。

3.创建LoggerAspect类

java">package com.m.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect
@Component
public class LoggerAspect {

    @Before(value = "execution(public int com.m.action_proxy.impl.CalImpl.*(..))")
    public void before(JoinPoint joinPoint){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        //获取参数列表
        String args = Arrays.toString(joinPoint.getArgs());
        System.out.println(name+"的参数是:"+args);
    }


    @After("execution(public int com.m.action_proxy.impl.CalImpl.*(..))")
    public void after(JoinPoint joinPoint){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法结束");
       
    }

    @AfterReturning(value = "execution(public int com.m.action_proxy.impl.CalImpl.*(..)))",returning = "result")
    public void afterReturning(JoinPoint joinPoint,Object result){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法的结果是:"+result);
        System.out.println("---------------------------------");
    }

    @AfterThrowing(value = "execution(public int com.m.action_proxy.impl.CalImpl.*(..)))",throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint,Exception exception){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法抛出异常:"+exception);
    }
}

方法注解:

  • @Before:表示切面方法执行的时机是业务方法执行之前。

  • @After:表示切面方法执行的时机是业务方法执行之后。

  • @AfterReturning:表示切面方法执行的时机是业务方法return之后。

  • @AfterThrowing:表示切面方法执行的时机是业务方法抛出异常之后。

  • execution(public int com.southwind.util.CalImpl.*(…)):表示切入点是com.southwind.util包下CalImpl类中的所有方法,即CalImpl所有方法在执行时会优先执行切面方法。






备注:最近来手感,写了个类似Tomcat服务

github地址:https://github.com/cnamep001/my_tomcat.git







http://www.niftyadmin.cn/n/1847227.html

相关文章

HDU-1814 Peaceful Commission (2-SAT暴力模板 暴力染色+字典序最小)

链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1814 题意&#xff1a;多组样例。2n个人。每两个为一个党派的人&#xff0c;m个互斥关系。每个党派选一个人&#xff0c;总共n个人。有解的话输出字典序最小的。 思路&#xff1a;赤果果的2-SAT题。先说说2-SAT吧…

2-SAT学习

慢慢填坑。。。。。。。。。。。 学习博客&#xff08;写的也忒好了。。。&#xff09;&#xff1a;https://blog.csdn.net/jarjingx/article/details/8521690 2-SAT题步骤&#xff1a; 1.建图&#xff1a;根据选谁必须选谁的方式建图 2.tarjan&#xff1a;求强连通分量缩点…

将Vim改造为强大的IDE

1、安装Vim和Vim基本插件 首先安装好Vim和Vim的基本插件。这些使用apt-get安装即可&#xff1a; lingdubuntu:~/arm$sudo apt-get install vim vim-scripts vim-doc 其中vim-scripts是vim的一些基本插件&#xff0c;包括语法高亮的支持、缩进等等。 vim中文帮助文档tar包下…

POJ - 3683 Priest John's Busiest Day(2-SAT模板)

链接&#xff1a;http://poj.org/problem?id3683 题意&#xff1a;有n个婚礼需要主持。每个婚礼有两个时间段可以主持&#xff0c;求一个时间不冲突的主持n个婚礼的时间安排方案。 思路&#xff1a;显然是个2-SAT题&#xff0c;若将每个婚礼的两个时间段视为一个集合的两个元…

[JavaScript学习笔记]JavaScript零基础入门导读(都是细节,我已收藏!)

JavaScript零基础入门导读按照下面博客的顺序看就对了&#xff01;这篇博客算是一个目录吧&#xff01;&#xff01;&#xff01;零基础入门&#xff0c;算是过了一遍JavaScript啦&#xff0c;完结撒花啦啦啦&#xff01;JS三组成三位置三输入输出(JS三相之力,强得明显&#xf…

[剑指offer]JT62---二叉搜索树的第k个结点(二叉树有个江湖规矩!)

剑指offer第六十二题题目如下思路与代码题目如下 思路与代码 二叉树江湖规矩&#xff1a;左结点<根结点<右结点 那就很简单了&#xff0c;深搜&#xff0c;走左节点&#xff0c;n&#xff0c;没了再右节点。 注意n是先左节点递归再n&#xff0c;所以第一个n是最左节点。…

2019牛客暑期多校训练营(第八场)A All-one Matrices(单调栈+前缀和+思维)

链接&#xff1a;https://ac.nowcoder.com/acm/contest/888/A 题意&#xff1a;给出一个只含0或1的n*m的矩阵。求有多少个全是1的极大子矩阵。 思路&#xff1a;预处理每一行中每一列连续1的高度&#xff08;h[i][j]表示从第i行第j列开始向上有多少个连续的1。&#xff09;和…

[剑指offer]JT63---数据流中的中位数(和ccf大中小一个意思!)

剑指offer第六十三题题目如下代码与思路题目如下 代码与思路 规定了要两个方法&#xff0c;那么我们要先搞一个vector吧 insert的时候找一下插入的位置 或者就在后面随意push&#xff0c;找中位数的时候sort()一下就可以了 我觉得吧&#xff0c;这个题&#xff0c;呵呵&…