• Spring的AOP


    一、理解:

    AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

    OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。

    AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

    使用"横切"技术,AOP把软件系统分为两个部分:核心关注点横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

    二、面向切面编程:

    (1)通知(增强)Advice

      通知定义了切面是什么以及何时使用,应该应用在某个方法被调用之前?之后?还是抛出异常时?等等。

    (2)连接点 Join point

      连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时,抛出异常时,甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程中,并添加新的行为。

    (3)切点 Pointcut

      切点有助于缩小切面所通知的连接点的范围。如果说通知定义了切面的“什么”和“何时”的话,那么切点就定义了“何处”,切点会匹配通知所要织入的一个或多个连接点,一般常用正则表达式定义所匹配的类和方法名称来指定这些切点。

    (4)切面 Aspect

      切面是通知和切点的结合。通知和切点定义了切面的全部内容——它是什么,在何时何处完成其功能。

    (5)引入 Introduction

      引入允许我们向现有的类添加新方法或属性,从而无需修改这些现有类的情况下,让他们具有新的行为和状态。

    (6)织入 Weaving

      在过去我常常把织入与引入的概念混淆,我是这样来辨别的,“引入”我把它看做是一个定义,也就是一个名词,而“织入”我把它看做是一个动作,一个动词,也就是切面在指定的连接点被织入到目标对象中。

    总结一下:

      通知包含了需要用于多个应用对象的横切行为;连接点是程序执行过程中能够应用通知的所有点;切点定义了通知被应用的具体位置(在哪些连接点)。其中关键的概念是切点定义了哪些连接点会得到通知(增强)。创建切点来定义切面所织入的连接点是AOP框架的基本功能。

      另外,Spring是基于动态代理的,所以Spring只支持方法连接点,而像AspectJ和JBoss除了方法切点,它们还提供字段和构造器接入点。如果需要方法拦截之外的连接点拦截功能,则可以利用AspectJ来补充SpringAOP的功能。

    三、在Spring中的使用方式:

    注:如果spring配置文件xml中存在

          <!-- 扫描注解组件并且自动的注入spring beans中.   例如,他会扫描@Controller 和@Service下的文件.所以确保此base-package设置正确. -->  
          <!-- 扫描controller(controller层注入) -->
          <context:component-scan base-package="com.spring"/>

    则在配置beans.xml时不需要再添加

    <bean id="userService" class="com.spring.service.impl.UserServiceImpl"/>

    测试时

    package com.spring.test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import com.spring.service.UserService;
    public class Test {
    @Resource
    private UserService userService;
    public static void main(String[] args) { userService.update(2); userService.add(); } }

    1、通过Spring的API实现AOP:

    第一步:

    public interface UserService {
    public void add();
    public void update(int a);
    public void delete();
    public void search();
    }

    第二步:

    public class UserServiceImpl implements UserService {
    @Override
    public void add() {
    System.out.println("增加用户");
    }
    @Override
    public void update(int a) {
    System.out.println("修改用户");
    }
    @Override
    public void delete() {
    System.out.println("删除用户");
    }
    @Override
    public void search() {
    System.out.println("查询用户");
    }

    第三步:实现MethodBeforeAdvice,AfterReturningAdvice的接口,Spring框架当中为我们提供了很多中通知。

    public class Log implements MethodBeforeAdvice{
    /**
    * @param method 被调用方法对象
    * @param args 被调用的方法的参数
    * @param target 被调用的方法的目标对象
    * */
    @Override
    public void before(Method method, Object[] args, Object target)
    throws Throwable {
    System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行");
    }
    }
    public class AfterLog implements AfterReturningAdvice{
    /**
    * 目标方法执行后执行的通知
    * returnValue--返回值
    * method 被调用的方法对象
    * args 被调用的方法对象的参数
    * target 被调用的方法对象的目标对象
    * */
    @Override
    public void afterReturning(Object returnValue, Method method,
    Object[] args, Object target) throws Throwable {
    System.out.println(target.getClass().getName()+"的"+method.getName()+"被成功执行,返回值是:"+returnValue);
    }
    }
    import java.lang.reflect.Method;
    import org.springframework.aop.ThrowsAdvice;
    public class ExceptionLog implements ThrowsAdvice {
    public void afterThrowing(Method method,Exception ex) throws Throwable {
    }
    }

    第四步:配置beans.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="userService" class="com.spring.service.impl.UserServiceImpl"/>
    <!-- 这个切面也要配置成bean-->
    <bean id="log" class="com.spring.advice.Log"/>
    <bean id="afterLog" class="com.spring.advice.AfterLog"></bean>
    <aop:config>
    <!--切入点,需要告诉方法在什么去执行
    expression="execution(* com.spring.service.impl.*.*(..))"
    第一个* 表示所有的返回值,然后就是包名
    第二个*表示所有的类对象
    第三个*表示类对象所有的方法
    第四个*表示所有方法下面的带参数的方法或者是不带参数的方法
    -->
    <aop:pointcut expression="execution(* com.spring.service.impl.*.*(..))" id="pointcut"/>
    <!-- 在所有的方法中都切入前置通知-->
    <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
    </beans>

    第五步:测试:

    package com.spring.test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import com.spring.service.UserService;
    public class Test {
    public static void main(String[] args) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
    UserService userService = (UserService)ac.getBean("userService");
    userService.update(2);
    userService.add();
    }
    }

    第二种方式:自定义类来实现AOP,不实现spring的自带的通知

    第一步:重新通知

    public class Log {
    public void before(){
    System.out.println("方法执行前");
    }
    public void after(){
    System.out.println("方法执行后");
    }
    }

    第二步:重新写配置文件

    <?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="userService" class="com.spring.service.impl.UserServiceImpl"/>
    <!-- 这个切面也要配置成bean-->
    <bean id="log" class="com.spring.advice.Log"/>
    <aop:config>
    <!--切入点,需要告诉方法在什么去执行
    expression="execution(* com.spring.service.impl.*.*(..))"
    第一个* 表示所有的返回值,然后就是包名
    第二个*表示所有的类对象
    第三个*表示类对象所有的方法
    第四个*表示所有方法下面的带参数的方法或者是不带参数的方法
    -->
    <aop:aspect ref="log">
    <aop:pointcut expression="execution(* com.spring.service.impl.*.*(..))" id="pointcut"/>
    <aop:before method="before" pointcut-ref="pointcut"/>
    <aop:after method="after" pointcut-ref="pointcut"/>
    </aop:aspect>
    </aop:config>
    </beans>

    第三种方式:通过注解实现AOP

    第一步:修改log

    package com.spring.advice;
    import java.lang.reflect.Method;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.aop.MethodBeforeAdvice;
    @Aspect
    public class Log {
    @Before("execution(* com.spring.service.impl.*.*(..))")
    public void before(){
    System.out.println("方法执行前");
    }
    @After("execution(* com.spring.service.impl.*.*(..))")
    public void after(){
    System.out.println("方法执行后");
    }
    @Around("execution(* com.spring.service.impl.*.*(..))")
    public Object around(ProceedingJoinPoint jp) throws Throwable{
    System.out.println("环绕前");
    System.out.println("方法"+jp.getSignature());
    Object result=jp.proceed();
    System.out.println("环绕后");
    return result;
    }
    }

    第二步:修改beans.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="userService" class="com.spring.service.impl.UserServiceImpl"/>
    <!-- 这个切面也要配置成bean-->
    <bean id="log" class="com.spring.advice.Log"/>
    <aop:aspectj-autoproxy/>
    </beans>
  • 相关阅读:
    Nginx常用命令
    Nginx进程模型
    华为联运游戏或应用审核驳回:使用花币充值时,对支付延时处理不当,导致商品不到账
    使用Data Ability读取系统设置项
    100个HarmonyOS 2.0开发者Beta公测名额,限时认领!
    【有奖活动】HarmonyOS开发者创新大赛颁奖典礼丨见证星星之火燃爆盛夏
    你其实可以更快!用Toolkit拖拽式编码方法帮你快速提升开发效率
    真机调试设备不够?华为AGConnect云调试帮你忙
    华为后台某应用商品展示价格币种随其他应用配置而变化
    HMS Core.Sparkle影音娱乐创新沙龙邀您参加
  • 原文地址:https://www.cnblogs.com/Neonuu/p/8883375.html
Copyright © 2020-2023  润新知