宠物寄养网站毕业设计,响应式网站检测工具,东莞专业网站设计咨询,推广引流要怎么做比较好文章目录 一、初识面向切面编程#xff08;AOP#xff09;1.1 什么是 AOP1.2 AOP的应用场景1.3 Aop 在 Spring 中的作用1.3.1 Aop 的核心概念 1.4 使用 Spring 实现 AOP1.4.1 方式一#xff1a;使用 Spring API 接口实现 AOP 【主要是SpringAPI接口实现】1.4.2 方式二#… 文章目录 一、初识面向切面编程AOP1.1 什么是 AOP1.2 AOP的应用场景1.3 Aop 在 Spring 中的作用1.3.1 Aop 的核心概念 1.4 使用 Spring 实现 AOP1.4.1 方式一使用 Spring API 接口实现 AOP 【主要是SpringAPI接口实现】1.4.2 方式二自定义类来实现 AOP【主要是切面定义】1.4.3 方式三使用注解实现 AOP 一、初识面向切面编程AOP 在以往的企业开发过程中一些已经写完的功能可以会在原本的基础上进行扩展这个时候就需要去修改原有的代码将新扩展的内容完善进去。但是这个动作其实是企业级开发的大忌因为原本好用的代码很可能因为新增的内容导致出现问题。 而解决这个问题会用到代理模式将要新扩展的功能维护到代理角色中再用代理角色去调用真实角色来实现功能的扩展这样做不但将新扩展的功能实现类原本的功能代码也无需变动更加稳妥。而这也是 Spring AOP 的实现机制。 1.1 什么是 AOP AOPAspect Oriented Programming意为面向切面编程通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续是软件开发中的一个热点也是Spring框架中的一个重要内容是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离从而使得业务逻辑各部分之间的耦合度降低提高程序的可重用性同时提高了开发的效率。 如下图所示AOP 就是通过一些方式在原有业务逻辑不变的情况下将一些扩展功能完成 1.2 AOP的应用场景 日志记录 记录调用方法的入参和结果返参。 用户的权限验证 验证用户的权限放到AOP中与主业务进行解耦。 性能监控 监控程序运行方法的耗时找出项目的瓶颈。 事务管理 控制Spring事务Mysql事务等。 AOP可以拦截指定的方法并且对方法增强比如事务、日志、权限、性能监测等增强而且无需侵入到业务代码中使业务与非业务处理逻辑分离。 1.3 Aop 在 Spring 中的作用 AOP 采取横向抽取机制动态代理取代了传统纵向继承机制的重复性代码其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。 主要作用是分离功能性需求和非功能性需求使开发人员可以集中处理某一个关注点或者横切逻辑减少对业务代码的侵入增强代码的可读性和可维护性。 简单的说AOP 的作用就是保证开发者在不修改源代码的前提下为系统中的业务组件添加某种通用功能。 1.3.1 Aop 的核心概念 提供声明式事务允许用户自定义切面 横切关注点 跨越应用程序多个模块的方法或功能。即是与我们业务逻辑无关的但是我们需要关注的部分就是横切关注点。如日志安全缓存事务等等… 切面ASPECT 横切关注点被模块化的特殊对象。即它是一个类。 通知Advice 切面必须要完成的工作。拦截到连接点之后对切入点增强的内容。即它是类中的一个方法。 目标Target 被代理的目标对象。 代理Proxy 指生成的代理对象 切入点PointCut 指需要对那些 JointPoint 进行拦截即被拦截的连接点 连接点JointPoint 指那些被拦截到的点在 Spring 中指可以被动态代理拦截目标类的方法 植入点Weaving 指把增强代码应用到目标上生成代理对象的过程 通俗理解 横切关注点在业务代码种需要新增的业务即为关注点 切面将关注点维护成一个类即新增的业务就是切面 通知切面中具体的方法也就是具体需要完成的业务就是通知。 目标即需要在那段业务新增业务代码即目标对象。 代理代理目标对象的对象 切入点需要通知在那个位置执行新的业务代码 注目标和代理被 Spring 完成了InvocationHandler、Proxy Spring AOP中通过 “通知Advice” 定义横切逻辑Spring中支持5种类型的Advice即AOP在不改变原有代码的情况下去增加新的功能。
通知类型连接点Before前置通知通知方法在目标方法调用之前执行前置通知不会影响目标方法的执行除非此处抛出异常After后置通知通知方法在目标方法返回或者异常后调用必然会执行After-Returning最终通知通知方法在目标方法返回后调用如果连接点抛出异常则不会执行After-Throwing抛出异常后通知通知方法在目标方法抛出异常后调用Around环绕通知环绕目标方法的通知例如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它可以选择是否继续执行目标方法或直接返回自定义的返回值又或抛出异常将执行结束。
注目标方法就是连接点 1.4 使用 Spring 实现 AOP 1.4.1 方式一使用 Spring API 接口实现 AOP 【主要是SpringAPI接口实现】 创建 Maven 项目并在 pom.xml 中引入如下依赖使用 AOP 织入需要此依赖 !-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --dependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.4/version/dependency在service包下定义UserService业务接口和UserServiceImpl实现类 UserService 接口 public interface UserService {void add();void query();void delete();void update();
}UserServiceImpl 实现类 public class UserServiceImpl implements UserService {Overridepublic void add() {System.out.println(新增一个用户);}Overridepublic void query() {System.out.println(查询用户信息);}Overridepublic void delete() {System.out.println(删除一个用户);}Overridepublic void update() {System.out.println(修改用户信息);}
}在 log 包下定义 一个前置增强和一个后置增强类 前置通知增强类 import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;//MethodBeforeAdvice : 前置通知
public class BeforeLog implements MethodBeforeAdvice {/** method要执行的目标对象的方法* args参数* target目标对象* */Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println(target.getClass().getName() 的 method.getName() 被执行了);}
}后置通知增强类 import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;// AfterReturningAdvice : 后置通知
public class AfterLog implements AfterReturningAdvice {/** returnValue 返回值* method要执行的目标对象的方法* args参数* target目标对象* */Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println(执行了method.getName()方法返回结果为returnValue);}
}最后去 spring 的文件中注册 , 并实现aop切入实现 , 注意导入约束配置 applicationContext.xml 文件 ?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd!--注册bean--bean idafterLog classcom.sys.log.AfterLog/bean idbeforeLog classcom.sys.log.BeforeLog/bean iduserService classcom.sys.service.impl.UserServiceImpl/!--配置 Spring aop需要导入aop约束--!--实现 aop 的方式一使用原生 Spring API接口--aop:config!--配置切入点execution 表达式execution(要执行的位置)execution(* *) 第一个 * 代表返回值的类型任意第二个 * 代表类如果为 * 就代表所有类execution(* com.sys.XXX.*(..)).*(..)表示任何方法名括号表示参数两个点表示任何参数类型--aop:pointcut idpointcut expressionexecution(* com.sys.service.impl.UserServiceImpl.*(..))/!--配置 Advice通知--!--前置加后置约等于环绕通知--aop:advisor advice-refafterLog pointcut-refpointcut/aop:advisor advice-refbeforeLog pointcut-refpointcut//aop:config/beansSpring AOP切入点Pointcut – execution表达式 创建 MyTest 测试类 public class MyText {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);// 需要注意的是AOP的代理是动态代理也就是此处代理的并不是实现类而是实现类实现的接口UserService userService (UserService) context.getBean(userService);userService.add();userService.update();userService.query();userService.delete();}
}执行结果 因为接口定义的方法都是 Void 所以没有返回值 1.4.2 方式二自定义类来实现 AOP【主要是切面定义】 不使用 Spring 提供的 API 接口使用自定义的 diy 类搭配 xml 的 aop 配置实现 创建 diy 工具类 public class DiyPointCut {public void before(){System.out.println(方法执行前);}public void after(){System.out.println(方法执行后);}
}创建 Beans.xml ?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd!-- 将 Diy 工具类注册到 SPring 容器种 --bean iddiyPointCut classcom.sys.diy.DiyPointCut/bean iduserService classcom.sys.service.impl.UserServiceImpl/!-- 配置 aop --aop:config!--自定义切面ref 要引用的类--aop:aspect refdiyPointCut!--配置切入点--aop:pointcut idpointcut expressionexecution(* com.sys.service.impl.UserServiceImpl.*(..))/!--配置通知before:前置通知after后置通知--aop:before methodbefore pointcut-refpointcut/aop:after methodafter pointcut-refpointcut//aop:aspect/aop:config/beans修改 MyTest其他代码内容不变 public class MyTest {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(Beans.xml);// 需要注意的是AOP的代理是动态代理也就是此处代理的并不是实现类而是实现类实现的接口UserService userService (UserService) context.getBean(userService);userService.add();System.out.println(-------------------------------------------------);userService.update();System.out.println(-------------------------------------------------);userService.query();System.out.println(-------------------------------------------------);userService.delete();}
}执行结果 1.4.3 方式三使用注解实现 AOP Aspect 被该注解标注的类就是一个切面 Before 标注切面类中的方法为前置通知 参数需要传入切入点即 execution 表达式 After 标注切面类中的方法为后置通知 参数需要传入切入点即 execution 表达式 Around 标注切面类中的方法为环绕通知 参数需要传入切入点即 execution 表达式 被标记为环绕通知的方法还需要搭配 proceed() 来完成通知如果没有该方法那么切入点对应的方法不执行也可以理解为这个方法就是执行切入点中的方法用的 proceed() : 通过这个方法判断切入点中的方法在环绕通知中的那个位置执行 代码示例(前置通知和后置通知) 新增 Diy 切面类 Aspect // 将该类标记为一个切面
public class AnnotationPointCut {// 将该方法标记为前置通知Before(execution(* com.sys.service.impl.UserServiceImpl.*(..)))public void before(){System.out.println(方法执行前);}// 将该方法标记为后置通知After(execution(* com.sys.service.impl.UserServiceImpl.*(..)))public void after(){System.out.println(方法执行后);}
}修改 Beans.xml 开启注解支持 ?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsdbean iduserService classcom.sys.service.impl.UserServiceImpl/!--方式三使用注解--bean idannotationPointCut classcom.sys.diy.AnnotationPointCut/!--开启aop注解支持 JDK(默认是 proxy-target-classfalse) cglibproxy-target-classtrue--aop:aspectj-autoproxy//beans其他代码不变运行测试类执行结果 环绕通知代码示例 修改 Diy 切面类 Aspect // 将该类标记为一个切面
public class AnnotationPointCut {Around(execution(* com.sys.service.impl.UserServiceImpl.*(..)))public void around(ProceedingJoinPoint jp) throws Throwable{System.out.println(环绕前);Signature signature jp.getSignature();// 获得签名System.out.println(signature:signature);jp.proceed(); //执行方法System.out.println(环绕后);}}其他代码不变运行测试类执行结果