关于aop:聊聊如何通过APTAST来实现AOP功能

前言如果有应用过spring aop性能的小伙伴,应该都会晓得spring aop次要是通过动静代理在运行时,对业务进行切面拦挡操作。明天咱们就来实现一下如何通过APT+AST在编译期时实现AOP性能。不过在此之前先科普一下APT和AST相干内容 APT(注解处理器)apt能够查看我之前写过的文章聊聊如何使用JAVA注解处理器(APT) AST(形象语法树)什么是AST形象语法树(Abstract Syntax Tree,AST),是源代码语法结构的一种形象示意。它以树状的模式体现编程语言的语法结构,树上的每个节点都示意源代码中的一种构造。比方包、类型、修饰符、运算符、接口、返回值都能够是一个语法结构。 示例: package com.example.adams.astdemo;public class TestClass { int x = 0; int y = 1; public int testMethod(){ int z = x + y; return z; }}对应的形象语法树如下: java的编译过程重点关注步骤一和步骤二生成AST的过程 步骤一:词法剖析,将源代码的字符流转变为 Token 列表。 通过词法分析器剖析源文件中的所有字符,将所有的单词或字符都转化成符合规范的Token 规范化的token能够分成一下三种类型: java关键字:public, static, final, String, int等等;自定义的名称:包名,类名,办法名和变量名;运算符或者逻辑运算符等符号:+、-、*、/、&&,|| 等等。 步骤二: 语法分析,依据 Token 流来结构树形表达式也就是 AST。 语法树的每一个节点都代表着程序代码中的一个语法结构,如类型、修饰符、运算符等。通过这个步骤后,编译器就根本不会再对源码文件进行操作了,后续的操作都建设在形象语法树之上。 AST的利用场景AST 定义了代码的构造,通过操作 AST,咱们能够精准地定位到申明语句、赋值语句、运算语句等,实现对源代码的剖析、优化、变更等操作。 注: AST操作属于编译器级别,对程序运行齐全没有影响,效率绝对其余AOP更高 java形象语法树罕用API类介绍JCTreeJCTree 是语法树元素的基类,蕴含一个重要的字段 pos,该字段用于指明以后语法树节点(JCTree)在语法树中的地位,因而咱们不能间接用 new 关键字来创立语法树节点,即便创立了也没有意义。 重点介绍几个JCTree的子类: 1、JCStatement:申明语法树节点,常见的子类如下 JCBlock:语句块语法树节点JCReturn:return 语句语法树节点JCClassDecl:类定义语法树节点JCVariableDecl:字段 / 变量定义语法树节点2、JCMethodDecl:办法定义语法树节点3、JCModifiers:拜访标记语法树节点4、JCExpression:表达式语法树节点,常见的子类如下 ...

April 25, 2023 · 7 min · jiezi

关于aop:Spring-AOP

1. 概述从实现的角度来说,代理分为基于类的代理和基于接口的代理,基于接口的代理有 动态代理和 动静代理,而基于类的代理须要依赖第三方库,比方 cglib,cglib的代理在运行时动静生成字节码文件来实现代理。 2. 动态代理在编译期间就曾经实现代理2.1 实现动态代理的必要条件基于接口或者抽象类代理类实现接口或者继承抽象类,通过构造函数传入指标对象重写办法,通过指标对象去执行业务逻辑而代理对象去执行与业务不想关的逻辑2.2 示例代码public interface UserService { /** * 增加 * @param email 邮箱 * @return 受影响的行数 */ int add(String email);}public class UserServiceImpl implements UserService { @Override public int add(String email) { System.out.println(String.format("email:%s", email)); return 1; }}public class UserServiceProxyImpl implements UserService { private final UserService targetObject; public UserServiceProxyImpl(UserService targetObject) { this.targetObject = targetObject; } @Override public int add(String email) { System.out.println("begin transaction"); int affectedRow = targetObject.add(email); System.out.println("commit transaction"); System.out.println(String.format("affected row:%s", affectedRow)); return affectedRow; }}2.4 动态代理的毛病只能代理一个实现类或接口,无奈做到代理多个类,这样照成了代理类的作用范畴的局限性对于不须要代理的接口办法也须要实现,造成的代码的冗余,扩大难的问题依赖于接口3. 动静代理在运行期间动静生成字节码文件3.1 示例代码public class ServiceProxy implements InvocationHandler { private final Object targetObject; private ClassLoader classLoader; private Class<?>[] interfaces; public ServiceProxy(Object targetObject) { this.targetObject = targetObject; this.classLoader = targetObject.getClass().getClassLoader(); this.interfaces = targetObject.getClass().getInterfaces(); } public Object getProxyObject() { return Proxy.newProxyInstance(classLoader, interfaces, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(String.format("%s.%s", targetObject.getClass().getName(), method.getName())); System.out.println("begin transaction"); if (args != null) { System.out.println(String.format("params:%s", Arrays.toString(args))); } Object retVal = method.invoke(targetObject, args); System.out.println("commit transaction"); System.out.println(String.format("affected row:%s", retVal)); return retVal; }}public interface UserService { /** * 增加 * @param email 邮箱 * @return 受影响的行数 */ int add(String email);}public class UserServiceImpl implements UserService { @Override public int add(String email) { return 1; }}3.2 与动态代理的区别动态代理在编译期就曾经实现,而动静代理在运行时实现动态代理只能代理一个类,而动静代理能够代理多个类都依赖与接口动态代理扩大难以及难以保护,而动静代理代理了接口中的所有的办法,达到了通用性。因为动静代理代理了接口中的所有办法,如果指标对象须要扩大接口办法且不依赖代理对象就须要关注代理的实现细节。4. CgLig 代理cglib全称Code Generation Libary,即 代码生成库,能可能在运行时生成子类对象从而达到对指标对象扩大的性能。 ...

November 27, 2022 · 3 min · jiezi

关于aop:AOP如何实现及实现原理

1. AOP简介置信大家或多或少的理解过AOP,都晓得它是面向切面编程,在网上搜寻能够找到很多的解释。这里我用一句话来总结:AOP是可能让咱们在不影响原有性能的前提下,为软件横向扩大性能。 那么横向扩大怎么了解呢,咱们在WEB我的项目开发中,通常都恪守三层准则,包含管制层(Controller)->业务层(Service)->数据层(dao),那么从这个构造下来的为纵向,它具体的某一层就是咱们所说的横向。咱们的AOP就是能够作用于这某一个横向模块当中的所有办法。 咱们在来看一下AOP和OOP的区别:AOP是OOP的补充,当咱们须要为多个对象引入一个公共行为,比方日志,操作记录等,就须要在每个对象中援用公共行为,这样程序就产生了大量的反复代码,应用AOP能够完满解决这个问题。 接下来介绍一下提到AOP就必须要理解的知识点: 切面:拦截器类,其中会定义切点以及告诉切点:具体拦挡的某个业务点。告诉:切面当中的办法,申明告诉办法在指标业务层的执行地位,告诉类型如下: 1. 前置告诉:@Before 在指标业务办法执行之前执行2. 后置告诉:@After 在指标业务办法执行之后执行3. 返回告诉:@AfterReturning 在指标业务办法返回后果之后执行4. 异样告诉:@AfterThrowing 在指标业务办法抛出异样之后5. 盘绕告诉:@Around 功能强大,可代替以上四种告诉,还能够控制目标业务办法是否执行以及何时执行2. 代码中实现举例下面曾经大略的介绍了AOP中须要理解的基本知识,也晓得了AOP的益处,那怎么在代码中实现呢?给大家举个例子:咱们当初有个学校管理系统,曾经实现了对老师和学生的增删改,又新来个需要,说是对老师和学生的每次增删改做一个记录,到时候校长能够查看记录的列表。那么问题来了,怎么样解决是最好的解决办法呢?这里我列举了三种解决办法,咱们来看下他的优缺点。 -最简略的就是第一种办法,咱们间接在每次的增删改的函数当中间接实现这个记录的办法,这样代码的反复度太高,耦合性太强,不倡议应用。 -其次就是咱们最长应用的,将记录这个办法抽离进去,其余的增删改调用这个记录函数即可,显然代码反复度升高,然而这样的调用还是没有升高耦合性。 -这个时候咱们想一下AOP的定义,再想想咱们的场景,其实咱们就是要在不扭转原来增删改的办法,给这个零碎减少记录的办法,而且作用的也是一个层面的办法。这个时候咱们就能够采纳AOP来实现了。 咱们来看下代码的具体实现: 首先我定义了一个自定义注解作为切点@Target(AnnotationTarget.FUNCTION) //注解作用的范畴,这里申明为函数@Order(Ordered.HIGHEST_PRECEDENCE) //申明注解的优先级为最高,假如有多个注解,先执行这个annotation class Hanler(val handler: HandlerType) //自定义注解类,HandlerType是一个枚举类型,外面定义的就是学生和老师的增删改操作,在这里就不展现具体内容了接下来就是要定义切面类了 @Aspect //该注解申明这个类为一个切面类@Componentclass HandlerAspect{ @Autowired private lateinit var handlerService: HandlerService @AfterReturning("@annotation(handler)") //当有函数正文了注解,将会在函数失常返回后在执行咱们定义的办法 fun hanler(hanler: Hanler) { handlerService.add(handler.operate.value) //这里是真正执行记录的办法 }}最初就是咱们原本的业务办法了 /** * 删除学生办法 */@Handler(operate= Handler.STUDENT_DELETE) //当执行到删除学生办法时,切面类就会起作用了,当学生失常删除后就会执行记录办法,咱们就能够看到记录办法生成的数据fun delete(id:String) {studentService.delete(id)}AOP实现原理咱们当初理解了代码中如何实现,那么AOP实现的原理是什么呢?之前看了一个博客说到,提到AOP大家都晓得他的实现原理是动静代理,显然我之前就是不晓得的,哈哈,然而置信阅读文章的你们肯定是晓得的。讲到动静代理就不得不说代理模式了, 代理模式的定义:给某一个对象提供一个代理,并由代理对象管制对原对象的援用。代理模式蕴含如下角色:subject:形象主题角色,是一个接口。该接口是对象和它的代理共用的接口; RealSubject:实在主题角色,是实现形象主题接口的类; Proxy:代理角色,外部含有对实在对象RealSubject的援用,从而能够操作实在对象。代理对象提供与实在对象雷同的接口,以便代替实在对象。同时,代理对象能够在执行实在对象操作时,附加其余的操作,相当于对实在对象进行封装。如下图所示: 那么代理又分为动态代理和动静代理,这里写两个小的demo,动静代理采纳的就是JDK代理。举个例子就是当初一个班上的学生须要交作业,当初由班长代理交作业,那么班长就是代理,学生就是被代理的对象。 3.1 动态代理首先,咱们创立一个Person接口。这个接口就是学生(被代理类),和班长(代理类)的公共接口,他们都有交作业的行为。这样,学生交作业就能够让班长来代理执行。 /** * Created by Mapei on 2018/11/7 * 创立person接口 */public interface Person { //交作业 void giveTask();}Student类实现Person接口,Student能够具体实施交作业这个行为 ...

November 23, 2022 · 3 min · jiezi

关于aop:because-it-is-a-JDK-dynamic-proxy-that-implements-问题

景象形容以下的SpringBoot 工程在启动的时候会启动失败。(SpringBoot 1.5.7-RELEASE)package com.example.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.transaction.annotation.EnableTransactionManagement;@SpringBootApplication@EnableTransactionManagementpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}package com.example.demo.controller;import com.example.demo.service.DemoServiceImpl;import javax.annotation.Resource;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class DemoController { @Resource private DemoServiceImpl demoService; @RequestMapping("/test") public String test() { return demoService.demo(); }}package com.example.demo.service;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Service("demoService")public class DemoServiceImpl implements DemoService{ @Override @Transactional public String demo() { return "DemoServiceImpl"; }}package com.example.demo.service;public interface DemoService { String demo();}报错信息***************************APPLICATION FAILED TO START***************************Description:The bean 'demoService' could not be injected as a 'com.example.demo.service.DemoServiceImpl' because it is a JDK dynamic proxy that implements: com.example.demo.service.DemoServiceAction:Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.如果只是解决如果不去深究起因,只是须要解决这个异样。那么有以下几种形式。只需实现其中任意一个即可。1. 批改EnableTransactionManagement注解参数DemoApplication 上的注解 @EnableTransactionManagement 变成 @EnableTransactionManagement(proxyTargetClass = false)2. 在application.properties配置文件中减少配置spring.aop.proxy-target-class=true3. 注入bean 的时候变更为应用其接口(最举荐)@Resourceprivate DemoServiceImpl demoService;改成: ...

April 28, 2022 · 1 min · jiezi

关于aop:Spring-AOP原理上

SpringAOP工作原理-上作为 Spring 体系里的大块头,AOP用起来是很爽,然而问你它是怎么实现的,你就懵逼。嘿嘿嘿 ~ 还是从 SpringBoot 的启动流程来讲起,看看定义切面后的启动流程。 先看咱们的测试例子: TestController.java : LogAspect.java : 接下来,从启动流程看,TestController 和 LogAspect是怎么创立的。 咱们找到 AbstractAutowireCapableBeanFactory#initializeBean() 办法,如图: 别问我怎么找到这个办法的,我不会通知你是打了九九八十一个断点调进去的 =。= 进入 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName) 办法,看下参数: 遍历到 AnnotationAwareAspectJAutoProxyCreator 这个processor的时候,debug进去,能够看到: 这个 wrapIfNecessary()办法就很要害了,再点进去: 能够看到这一步里,先是找到所有的告诉器(拦截器或者增强器),而后接下来创立proxy: 点击createProxy(),进入,看外围代码代码: protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { …… ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); …… Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } ClassLoader classLoader = getProxyClassLoader(); if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) { classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader(); } return proxyFactory.getProxy(classLoader); }能够看到,这里都是对 proxyFactory 进行设置的。点击 proxyFactory.getProxy(classLoader) ,始终追到 ...

January 14, 2022 · 1 min · jiezi

关于aop:AOP-概念篇

Spring AOP 系列的第一篇 先介绍一下 AOP 相干的一些概念。 呈现的契机在事实中、咱们常常须要记录重要操作的流水以及打印相干的日志到日志文件 // 微信公众号:CoderLipublic class BizService01 { public void dealBiz(BizDto bizDto) { // 脱敏打印 + 统计上报到经营零碎 record(bizDto); // 业务操作 } private void record(BizDto bizDto){ // ..... }}当存在 n 多个这样的 Service 的时候、咱们进一步的操作可能是:将其抽取到一个公共的中央进行记录保护 // 微信公众号:CoderLipublic class BizService01 { public void dealBiz(BizDto bizDto) { // 脱敏打印 + 统计上报到经营零碎 RecordUtils.record(bizDto); // 业务操作 } }再进一步、咱们可能应用模板办法来设计。子类继承该根底服务 // 微信公众号:CoderLipublic abstract class BaseBizService { public void dealBiz(BizDto bizDto){ // 脱敏打印 + 统计上报到经营零碎 if (isRecord()) { RecordUtils.record(bizDto); } readDealBiz(bizDto); } protected abstract void readDealBiz(BizDto bizDto); protected boolean isRecord(){ return true; }}这样子貌似是能解决对立解决非核心业务、然而如果咱们还须要进行其余的一些非核心业务解决的时候、比如说、权限测验、性能监控等、并且这些非核心业务他们的程序、在每一个业务场景中、程序可能不一样、是否执行这些非核心业务也是不确定的、那么单纯靠模板办法来解决的话、会显得十分费劲、甚至能够说、这种变动的流程不适宜模板办法了曾经。 ...

December 18, 2021 · 2 min · jiezi

关于aop:一文带你搞定AOP切面

摘要:AOP在spring中又叫“面向切面编程”,是对传统咱们面向对象编程的一个补充,次要操作对象就是“切面”,能够简略的了解它是贯通于办法之中,在办法执行前、执行时、执行后、返回值后、异样后要执行的操作。本文分享自华为云社区《一篇文搞懂《AOP面向切面编程》是一种什么样的体验?》,作者: 灰小猿。 一、什么是Spring的AOP?AOP在spring中又叫“面向切面编程”,它能够说是对传统咱们面向对象编程的一个补充,从字面上顾名思义就能够晓得,它的次要操作对象就是“切面”,所以咱们就能够简略的了解它是贯通于办法之中,在办法执行前、执行时、执行后、返回值后、异样后要执行的操作。相当于是将咱们本来一条线执行的程序在两头切开退出了一些其余操作一样。 在利用AOP编程时,依然须要定义公共性能,但能够明确的定义这个性能利用在哪里,以什么形式利用,并且不用批改受影响的类。这样一来横切关注点就被模块化到非凡的类里——这样的类咱们通常就称之为“切面”。 例如上面这个图就是一个AOP切面的模型图,是在某一个办法执行前后执行的一些操作,并且这些操作不会影响程序自身的运行。 AOP切面编程中有一个比拟业余的术语,我给大家罗切出来了: 当初大略的理解了AOP切面编程的基本概念,接下来就是实际操作了。 二、AOP框架环境搭建1、导入jar包目前比拟风行且罕用的AOP框架是AspectJ,咱们在做SSM开发时用到的也是AspectJ,应用该框架技术就须要导入它所反对的jar包, aopalliance.jaraspectj.weaver.jarspring-aspects.jar对于SSM开发所应用的所有jar包和相干配置文件我都已将帮大家筹备好了! 点击链接下载就能用。【全网最全】SSM开发必备依赖-Jar包、参考文档、罕用配置 2、引入AOP名称空间应用AOP切面编程时是须要在容器中引入AOP名称空间的, 3、写配置其实在做AOP切面编程时,最常应用也必备的一个标签就是,< aop:aspectj-autoproxy></aop:aspectj-autoproxy>, 咱们在容器中须要增加这个元素,当Spring IOC容器侦测到bean配置文件中的< aop:aspectj-autoproxy>元素时,会主动为与AspectJ切面匹配的bean创立代理。同时在当初的spring中应用AOP切面有两种形式,别离是AspectJ注解或基于XML配置的AOP, 上面我顺次和大家介绍一下这两种形式的应用。 三、基于AspectJ注解的AOP开发在上一篇文章中我也和大家将了对于spring中注解开发的弱小,所以对于AOP开发咱们同样也能够应用注解的模式来进行编写,上面我来和大家介绍一下如何应用注解形式书写AOP。 1、五种告诉注解首先要在Spring中申明AspectJ切面,只须要在IOC容器中将切面申明为bean实例。 当在Spring IOC容器中初始化AspectJ切面之后,Spring IOC容器就会为那些与 AspectJ切面相匹配的bean创立代理。 在AspectJ注解中,切面只是一个带有@Aspect注解的Java类,它往往要蕴含很多告诉。告诉是标注有某种注解的简略的Java办法。 AspectJ反对5种类型的告诉注解: @Before:前置告诉,在办法执行之前执行@After:后置告诉,在办法执行之后执行@AfterRunning:返回告诉,在办法返回后果之后执行@AfterThrowing:异样告诉,在办法抛出异样之后执行@Around:盘绕告诉,围绕着办法执行2、切入点表达式标准这五种告诉注解前面还能够跟特定的参数,来指定哪一个切面办法在哪一个办法执行时触发。那么具体操作是怎么样的呢? 这里就须要和大家介绍一个名词:“切入点表达式”,通过在注解中退出该表达式参数,咱们就能够通过表达式的形式定位一个或多个具体的连接点, 切入点表达式的语法格局标准是: execution([权限修饰符] [返回值类型] [简略类名/全类名] [办法名] ([参数列表])) 其中在表达式中有两个罕用的特殊符号: 星号“ * ”代表所有的意思,星号还能够示意任意的数值类型 “.”号:“…”示意任意类型,或任意门路下的文件, 在这里举出几个例子:表达式: execution( com.atguigu.spring.ArithmeticCalculator.(…)) 含意: ArithmeticCalculator接口中申明的所有办法。第一个“”代表任意修饰符及任意返回值。第二个“”代表任意办法。“…”匹配任意数量、任意类型的参数。若指标类、接口与该切面类在同一个包中能够省略包名。 表达式: execution(public ArithmeticCalculator.(…)) 含意: ArithmeticCalculator接口的所有私有办法 表达式: execution(public double ArithmeticCalculator.*(…)) 含意: ArithmeticCalculator接口中返回double类型数值的办法 表达式: execution(public double ArithmeticCalculator.*(double, …)) 含意: 第一个参数为double类型的办法。“…” 匹配任意数量、任意类型的参数。 表达式: execution(public double ArithmeticCalculator.*(double, double)) 含意: 参数类型为double,double类型的办法 ...

August 3, 2021 · 4 min · jiezi

关于aop:Spring-AOP相同切入点抽取和通知的优先级

雷同切入点的抽取 @Pointcut(value="execution(* com.zong.spring.User.add(..))")public void pointcut1(){}@Before(value="pointcut1()")public void before(){}@After(value="pointcut1()")public void after(){}告诉的优先级:当多个加强类对同一个办法进行加强时,应用@Order注解增加在加强类下面示意优先级,数字越小优先级越高 @Component@Aspect@Order(1)public class Proxy1{}@Component@Aspect@Order(3)public class Proxy2{}

June 18, 2021 · 1 min · jiezi

关于aop:AOP进行通知切面的步骤

1、根本配置1)在Spring的配置文件或配置类中,开启注解扫描2)应用注解创立被加强类和加强类对象3)在加强类上增加注解@Aspect4)在Spring配置文件中开启生成代理对象xml配置文件形式:<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 2、配置不同类型的告诉加强类(代理类) @Component@Aspectpublic class UserProxy{ //前置告诉 @Before(value="execution(* com.zong.spring.User.add(..))") public void before(){ System.out.println("before..."); } //后置告诉 @AfterReturning(value="execution(* com.zong.spring.User.add(..))") public void afterReturning(){ System.out.println("afterReturning..."); } //最终告诉 @After(value="execution(* com.zong.spring.User.add(..))") public void after(){ System.out.println("after..."); } //异样告诉 @AfterThrowing(value="execution(* com.zong.spring.User.add(..))") public void afterThrowing(){ System.out.println("afterThrowing..."); } //盘绕告诉 @Around(value="execution(* com.zong.spring.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint){ System.out.println("盘绕之前..."); //执行被加强的办法 proceedingJoinPoint.proceed(); System.out.println("盘绕之后..."); }}执行后果 盘绕之前...before..add..盘绕之后..after...afterReturning...异样执行后果 盘绕之前...Before...after...afterThrowing...

June 17, 2021 · 1 min · jiezi

关于aop:Spring中AOP操作

1、Spring个别是基于AspectJ实现AOP操作1)AspectJ是一个独立的AOP框架,非Spring的组成部分 2、AspectJ实现AOP操作的两种形式:1)基于XML配置文件实现2)基于注解实现(罕用) 3、导入AsepctJ须要的依赖包 4、切入点表达式1)作用:晓得对哪个类的哪个办法进行加强2)语法结构:execution(权限修饰符[类全门路]办法名称)示例1:execution( com.zong.spring.BookDao.add(..)) 示意所有权限,返回类型省略示例2execution( com.zong.spring.BookDao.(..))示例3execution( com.zong.spring..*(..))

June 17, 2021 · 1 min · jiezi

关于aop:AOP术语

1、连接点类中哪些办法能够被加强,这些办法就称为连接点 2、切入点理论被加强的办法,就称为切入点 3、告诉(加强)理论加强的逻辑局部就称为告诉分为:前置告诉后置告诉盘绕告诉(蕴含前置、后置)异样告诉(异样时执行)最终告诉(相似finally) 4、切面把告诉利用到切入点的过程就叫切面,是个动作

June 17, 2021 · 1 min · jiezi

关于aop:AOP原理

不批改原代码的前提下,在原性能上减少一个新性能,例如在登陆性能中新增权限性能管制 底层原理:动静代理两种状况1)有接口 应用JDK动静代理创立接口实现类代理对象2)没有接口 应用CGLIB创立以后类子类的代理对象 JDK动静代理实现代码示例 public interface UserDao { public int add(int a, int b);}public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { // TODO Auto-generated method stub System.out.println("执行"+a+"+"+b); return a+b; }}public class JdkProxy { public static void main(String[] args) { Class[] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao)Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1, 2); }}//创立代理对象class UserDaoProxy implements InvocationHandler{ //把此次加强的对象传进来 private Object obj; public UserDaoProxy(Object obj) { this.obj = obj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ //办法之前 System.out.println("办法之前执行"+method.getName()+"传递的参数:"+Arrays.toString(args)); //被加强的办法 Object res = method.invoke(obj, args); //办法之后 System.out.println("办法之后执行"+obj); return res; }}

June 16, 2021 · 1 min · jiezi

关于aop:如何低侵入的记录调用日志

前言前阵子敌人他老大叫他实现这么一个性能,就是低侵入的记录接口每次的申请响应日志,而后并统计每次申请调用的胜利、失败次数以及响应耗时,过后敌人的实现思路是在每个业务的controller的办法上加一个自定义注解,而后写一个aop,以这个自定义注解为pointcut来记录日志。 这种AOP+注解来实现日志记录,应该是很常见的实现形式。然而敌人在落地的时候,发现我的项目要加自定义注解的中央太多。前面我就跟他说,那就不写注解,间接以形如下 execution(* com.github.lybgeek.logaop.service..*.*(..))这样不行吗?他说他这个性能他老大是心愿给各个项目组应用,像我下面的办法,预计行不通,我就问他说为啥行不通,他说各个我的项目的包名都不一样,如果我那种思路,他就说这样在代码里poincut不得要这么写 execution(* com.github.lybgeek.a.service..*.*(..) || * com.github.lybgeek.b.service..*.*(..) || * com.github.lybgeek.c.service..*.*(..) )这样每次新加要日志记录,都得改切面代码,还不如用自定注解来的好。听完他的解释,我一脸黑人问号脸。于是就趁着5.1假期期间,写个demo实现下面的需要 业务场景低侵入的记录接口每次的申请响应日志,而后并统计每次申请调用的胜利、失败次数以及响应耗时这个业务需要应该算是很简略,实现的难点就在于低侵入,提到低侵入,我首先想到是使用者无需写代码,或者只需写大量代码或者仅需简略配置一下,最好能做到业务无感知。 实现伎俩我这边提供2种思路 javaagent + byte-buddyspringboot主动拆卸 + AOPjavaagent1、什么是javaagentjavaagent是一个简略优雅的java agent,利用java自带的instrument个性+javassist/byte-buddy字节码能够实现对类的拦挡或者加强。 javaAgent 是运行在 main办法之前的拦截器,它内定的办法名叫 premain ,也就是说先执行 premain 办法而后再执行 main 办法 2、如何实现一个javaagenta、必须实现premain办法示例: public class AgentDemo { public static void premain(String agentArgs, Instrumentation inst) { System.out.println("agentArgs : " + agentArgs); inst.addTransformer(new DefineTransformer(),true); } static class DefineTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { System.out.println("premain load Class:" + className); return classfileBuffer; } }}b、在META-INF目录增加MANIFEST.MF文档,内容形如下 ...

May 5, 2021 · 3 min · jiezi

关于springboot:模仿Cacheables实现方法拦截

背景在SpringBoot开发中,通过@Cacheable注解便能够实现办法级别缓存,如下 @GetMapping(value = "/user/detail") @Cacheable(value = "user", key = "#uid") public User deteail(@RequestParam(value = "uid") String uid) {...}Cacheable的逻辑 如果缓存中没有key为#uid的数据就执行detail函数并且把后果放到缓存中如果缓存中存在key为#uid的数据就间接返回,不执行detail函数通过Cacheable咱们能够十分不便的在代码中应用缓存,那么Cacheable是如何实现的,一开始认为是通过AOP实现,然而通过查看源码,发现跟AOP又有点不一样。 Cacheable原理如果要应用Cacheable就必须在启动类上加上@EnableCaching(),该注解定义如下 @Import(CachingConfigurationSelector.class)public @interface EnableCaching {...}CachingConfigurationSelector继承了AdviceModeImportSelector,次要看selectImports办法 public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching>{ //..... @Override public String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return getProxyImports(); case ASPECTJ: return getAspectJImports(); default: return null; } } private String[] getProxyImports() { List<String> result = new ArrayList<>(3); result.add(AutoProxyRegistrar.class.getName()); result.add(ProxyCachingConfiguration.class.getName()); if (jsr107Present && jcacheImplPresent) { result.add(PROXY_JCACHE_CONFIGURATION_CLASS); } return StringUtils.toStringArray(result); }}判断实现模式是基于代理(PROXY)还是ASPECTJ,Spring-AOP模式应用时代理模式,所以这边会走到getProxyImports这里getProxyImports中退出两个代理类,咱们次要看ProxyCachingConfiguration@Configuration@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public class ProxyCachingConfiguration extends AbstractCachingConfiguration { @Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor() { BeanFactoryCacheOperationSourceAdvisor advisor = new BeanFactoryCacheOperationSourceAdvisor(); advisor.setCacheOperationSource(cacheOperationSource()); advisor.setAdvice(cacheInterceptor()); if (this.enableCaching != null) { advisor.setOrder(this.enableCaching.<Integer>getNumber("order")); } return advisor; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public CacheOperationSource cacheOperationSource() { return new AnnotationCacheOperationSource(); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public CacheInterceptor cacheInterceptor() { CacheInterceptor interceptor = new CacheInterceptor(); interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager); interceptor.setCacheOperationSource(cacheOperationSource()); return interceptor; }}这里创立了几个类,咱们重点关注以下两个类 ...

March 15, 2021 · 2 min · jiezi

关于aop:代理模式AOP绪论

本篇能够了解为Spring AOP的铺垫,以前大略会用Spring框架提供的AOP,然而对AOP还不是很理解,于是打算零碎的梳理一下代理模式和AOP。简略的谈一下代理软件世界是对事实世界形象,所以软件世界的某些概念也不是凭空产生,也是从事实世界中脱胎而来,就像多态这个概念一样,Java官网出的指导书 《The Java™ Tutorials》在讲多态的时候,首先提到多态首先是一个生物学的概念。那么设计模式中的代理模式,咱们也能够认为是从事实世界中形象而来,在事实世界代理这个词也是很常见的,比方房产中介代理房东的房子,经纪人代理明星谈商演。基本上代理人都在肯定范畴内代理被代表人的事务。 那咱们为什么须要代理模式呢? 咱们事实上也能够从事实世界去寻找答案,为什么房东要找房产中介呢? 因为房东也是人,也有本人的生存,不可能将全身心都搁置在将本人的房屋出租上,不违心做扭转。那么软件世界的代理模式,我认为也是有着同样的起因,原来的某个对象须要再度承接一个性能,然而咱们并不违心批改对象从属的类,起因可能有很多,兴许旧的对象曾经对外应用,一旦批改兴许会有其余意想不到的反馈,兴许咱们没方法批改等等。起因有很多,同时对一个过来的类批改也不合乎开闭准则,对扩大凋谢,对批改关闭。于是咱们就心愿在不批改指标对象的性能前提下,对指标的性能进行扩大。 网上的大多数博客在讲代理模式的时候,大多都会从一个接口动手,而后需要是扩大实现对该接口实现类的加强,而后写代码演示。像是上面这样: public interface IRentHouse { /** * 实现该接口的类将可能对外提供房子 */ void rentHouse();}public class Landlord implements IRentHouse { @Override public void rentHouse() { System.out.println(" 我向你提供房子..... "); }}public class HouseAgent implements IRentHouse { @Override public void rentHouse() { System.out.println("在该类的办法之前执行该办法"); IRentHouse landlord = new Landlord(); landlord.rentHouse(); System.out.println("在该类的办法之后执行该办法"); }}public class Test { public static void main(String[] args) { IRentHouse landlord = new HouseAgent(); landlord.rentHouse(); }}测试后果: 许多博客在刚讲动态代理的时候通常会从这里动手,在不扭转原来类同时,对原来的类进行增强。对,这算是一个相当事实的需要,尤其是在原来的类在零碎中应用的比拟多的状况下,且运行比较稳定,一旦改变就算是再小心翼翼,也无奈保障对原来的零碎一点影响都没有,最好的办法是不改,那如何加强原有的指标对象,你新加强的个别就是要满足新的调用者的需要,那我就新增一个类吧,供你调用。很完满,那问题又来了,为什么各个博客都是从接口登程呢? ...

February 27, 2021 · 2 min · jiezi

关于aop:AOP的常用注解

@Aspect:作用:把以后类申明为切面类。@Before:作用:把以后办法看成是前置告诉。属性: value:用于指定切入点表达式,还能够指定切入点表达式的援用。 讲师:陈飞@AfterReturning作用:把以后办法看成是后置告诉。属性: value:用于指定切入点表达式,还能够指定切入点表达式的援用。@AfterThrowing作用:把以后办法看成是异样告诉。属性: value:用于指定切入点表达式,还能够指定切入点表达式的援用。@After作用:把以后办法看成是始终告诉。属性: value:用于指定切入点表达式,还能够指定切入点表达式的援用。@Around作用:把以后办法看成是盘绕告诉。属性: value:用于指定切入点表达式,还能够指定切入点表达式的援用。@Pointcut作用:指定切入点表达式属性: value:指定表达式的内容

January 14, 2021 · 1 min · jiezi

关于aop:AOP简介与作用

AOP简介与作用 AOPAspect Oriented Programming(AOP)是较为热门的一个话题。AOP,国内大抵译作“面向切面编程”。 “面向切面编程”,这样的名字并不是非常容易了解,且容易产生一些误导。笔者不止一次听到相似“OOP/OOD11行将掉队,AOP是新一代软件开发形式”这样的发言。而在AOP中,Aspect的含意,可能更多的了解为“切面”比拟适合。所以笔者更偏向于“面向切面编程”的译法。能够通过预编译形式和运行期动静代理实现在不批改源代码的状况下给程序动静对立增加性能的一种技术。AOP理论是GoF设计模式的连续,设计模式手不释卷谋求的是调用者和被调用者之间的解耦,进步代码的灵活性和可扩展性,AOP能够说也是这种指标的一种实现。利用对象只实现它们应该做的——实现业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的零碎级关注点,例如日志或事务反对。AOP次要性能日志记录,性能统计,安全控制,事务处理,异样解决等等wn及扩大 AOP次要用意将日志记录,性能统计,安全控制,事务处理,异样解决等代码从业务逻辑代码中划分进去,通过对这些行为的拆散,咱们心愿能够将它们独立到非领导业务逻辑的办法中,进而扭转这些行为的时候不影响业务逻辑的代码。arkdown Extra** 定义列表语法: 代码块假如在一个利用零碎中,有一个共享的数据必须被并发同时拜访,首先,将这个数据封装在数据对象中,称为Data Class,同时,将有多个拜访类,专门用于在同一时刻拜访这同一个数据对象。为了实现上述并发拜访同一资源的性能,须要引入锁Lock的概念,也就是说,某个时刻,当有一个拜访类拜访这个数据对象时,这个数据对象必须上锁Locked,用完后就立刻解锁unLocked,再供其它拜访类拜访。应用传统的编程习惯,咱们会创立一个抽象类,所有的拜访类继承这个形象父类,如下:abstract class Worker {abstract void locked();abstract void accessDataObject();abstract void unlocked();}accessDataObject()办法须要有“锁”状态之类的相干代码。 Java只提供了单继承,因而具体拜访类只能继承这个父类,如果具体拜访类还要继承其它父类,比方另外一个如Worker的父类,将无奈不便实现。 重用被打折扣,具体拜访类因为也蕴含“锁”状态之类的相干代码,只能被重用在相干有“锁”的场合,重用范畴很窄。 认真钻研这个利用的“锁”,它其实有下列个性:“锁”性能不是具体拜访类的首要或次要性能,拜访类次要性能是拜访数据对象,例如读取数据或更改动作。“锁” “锁”性能其实是这个零碎的一个纵向切面,波及许多类、许多类的办法。如上图: `因而,一个新的程序结构应该是关注零碎的纵向切面,例如这个利用的“锁”性能,这个新的程序结构就是aspect(方面)在这个利用中,“锁”方面(aspect)应该有以下职责:` * 1* 2提供一些必备的性能,对被拜访对象实现加锁或解锁性能。以保障所有在批改数据对象的操作之前可能调用lock()加锁,在它应用实现后,调用unlock()解锁。 AOP利用范畴很显著,AOP非常适合开发J2EE容器服务器,JBoss 4.0正是应用AOP框架进行开发。具体性能如下:Authentication 权限Caching缓存Context passing内容传递Error handling 错误处理Lazy loading 延时加载Debugging 调试logging, tracing, profiling and monitoring 记录跟踪 优化 校准Performance optimization性能优化Persistence 长久化Resource pooling资源池Synchronization 同步Transactions事务【AOP有必要吗?】 `当然,上述利用范例在没有应用AOP状况下,也失去了解决,例如JBoss 3.XXX也提供了上述利用性能,并且没有应用AOP。 然而,应用AOP能够让咱们从一个更高的抽象概念来了解软件系统,AOP兴许提供一种有价值的工具。能够这么说:因为应用AOP构造,JBoss 4.0的源码要比JBoss 3.X容易了解多了,这对于一个大型简单零碎来说是十分重要的。 从另外一个方面说,如同不是所有的人都须要关怀AOP,它可能是一种架构设计的抉择,如果抉择J2EE零碎,AOP关注的上述通用方面都曾经被J2EE容器实现了,J2EE利用零碎开发者可能须要更多地关注行业利用方面aspect。 传统的程序通常体现出一些不能天然地适宜繁多的程序模块或者是几个严密相干的程序模块的行为,AOP 将这种行为称为横切,它们逾越了给定编程模型中的典型职责界线。横切行为的实现都是扩散的,软件设计师会发现这种行为难以用失常的逻辑来思考、实现和更改。最常见的一些横切行为如上面这些:` * 1* 2* 3* 4* 5* 6* 71、日志记录,跟踪,优化和监控2、事务的解决3、长久化4、性能的优化5、资源池,如数据库连接池的治理6、零碎对立的认证、权限治理等7、利用零碎的异样捕获及解决8、针对具体行业利用的横切行为 `后面几种横切行为都曾经失去了亲密的关注,也呈现了各种有价值的利用,但兴许今后几年,AOP 对针对具体行业利用的奉献会成为令人关注的焦点。` * 1AOP实现我的项目AOP是一个概念,并没有设定具体语言的实现,它能克服那些只有单继承个性语言的毛病(如Java),AOP具体实现有以下几个我的项目: ...

January 14, 2021 · 1 min · jiezi

关于aop:SpringBoot强化篇八-Spring-AOP

Spring AOP简介AOP(Aspect Orient Programming)是一种设计思维,是软件设计畛域中的面向切面编程,它是面向对象编程(OOP)的一种补充和欠缺。它以通过预编译形式和运行期动静代理形式,实现在不批改源代码的状况下给程序动静对立增加额定性能的一种技术。AOP与OOP字面意思相近,但其实两者齐全是面向不同畛域的设计思维。理论我的项目中咱们通常将面向对象了解为一个动态过程(例如一个零碎有多少个模块,一个模块有哪些对象,对象有哪些属性),面向切面的运行期代理形式,了解为一个动静过程,能够在对象运行时动静织入一些扩大性能或管制对象执行。 AOP 利用场景剖析?理论我的项目中通常会将零碎分为两大部分,一部分是外围业务,一部分是非核业务。在编程实现时咱们首先要实现的是外围业务的实现,非核心业务个别是通过特定形式切入到零碎中,这种特定形式个别就是借助AOP进行实现。 AOP就是要基于OCP(开闭准则),在不扭转原有系统核心业务代码的根底上动静增加一些扩大性能并能够"管制"对象的执行。例如AOP利用于我的项目中的日志解决,事务处理,权限解决,缓存解决等等。 Spring AOP 利用原理剖析Spring AOP底层基于代理机制(动静形式)实现性能扩大: 如果指标对象(被代理对象)实现接口,则底层能够采纳JDK动静代理机制为指标对象创立代理对象(指标类和代理类会实现独特接口)。如果指标对象(被代理对象)没有实现接口,则底层能够采纳CGLIB代理机制为指标对象创立代理对象(默认创立的代理类会继承指标对象类型)。阐明:Spring boot2.x 中AOP当初默认应用的CGLIB代理,如果须要应用JDK动静代理能够在配置文件(applicatiion.properties)中进行如下配置: #cglib aop proxy#spring.aop.proxy-target-class=true#jdk aop proxyspring.aop.proxy-target-class=falseSpring 中AOP 相干术语剖析切面(aspect): 横切面对象,个别为一个具体类对象(能够借助@Aspect申明)。告诉(Advice):在切面的某个特定连接点上执行的动作(扩大性能),例如around,before,after等。连接点(joinpoint):程序执行过程中某个特定的点,个别指向被拦挡到的指标办法。切入点(pointcut):对多个连接点(Joinpoint)一种定义,个别能够了解为多个连接点的汇合。 Spring AOP疾速实际我的项目创立及配置第一步创立maven我的项目或在已有我的项目根底上增加AOP启动依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency>第二步定义业务层接口 package com.cy.pj.common.service;public interface MailService { boolean sendMail(String msg);}第三步定义业务层实现类 @Servicepublic class MailServiceImpl implements MailService{ @Override public boolean sendMail(String msg) {//ocp(开闭准则-->对扩大凋谢,对批改敞开) long t1=System.currentTimeMillis(); System.out.println("send->"+msg); long t2=System.currentTimeMillis(); System.out.println("send time:"+(t2-t1)); return true; }}咱们本人计算了执行工夫,然而违反了ocp准则,所以须要无侵入式扩大这个记录执行工夫的性能。咱们在这个类中增加外部类来实现两种形式的扩大。 package com.cy.pj.common.service;import org.springframework.stereotype.Service;@Servicepublic class MailServiceImpl implements MailService{ @Override public boolean sendMail(String msg) {//ocp(开闭准则-->对扩大凋谢,对批改敞开) //long t1=System.currentTimeMillis(); System.out.println("send->"+msg); //long t2=System.currentTimeMillis(); //System.out.println("send time:"+(t2-t1)); return true; }}//上面的两种设计理解?(基于原生形式实现性能扩大)//本人入手写子类重写父类办法进行性能扩大class TimeMailServiceImpl extends MailServiceImpl{//这种写法的原型就是CGLIB代理机制的形式(继承) @Override public boolean sendMail(String msg) { long t1=System.currentTimeMillis(); boolean flag=super.sendMail(msg); long t2=System.currentTimeMillis(); System.out.println("send time:"+(t2-t1)); return flag; }}//本人写兄弟类对指标对象(兄弟类)进行性能扩大,这种形式又叫组合class TimeMailServiceImpl2 implements MailService{//这种写法的原型就是JDK代理机制的形式(实现) private MailService mailService; public TimeMailServiceImpl2(MailService mailService){ this.mailService=mailService; } @Override public boolean sendMail(String msg) { long t1=System.currentTimeMillis(); boolean flag=mailService.sendMail(msg); long t2=System.currentTimeMillis(); System.out.println("send time:"+(t2-t1)); return flag; }}下来通过aop形式实现业务 ...

November 14, 2020 · 5 min · jiezi

关于aop:AOP

AOP概述1.什么是AOP?AOP是一种设计思维,在不批改源代码的状况下给程序动静对立增加额定性能的一种技术,如图: 2.AOP利用原理剖析AOP底层基于代理机制(动静形式)实现性能扩大:1):如果指标对象(被代理对象)实现接口,则底层能够采纳JDK动静代理机制为指标对象创立代理对象(指标类和代理类会实现独特接口)。2):如果指标对象(被代理对象)没有实现接口,则底层能够采纳CGLIB代理机制为指标对象创立代理对象(默认创立的代理类会继承指标对象类型)。如图: AOP默认应用CGLIB代理,如需应用JDK代理配置文件配置:spring.aop.proxy-target-class=false 基于JDK代理形式实现: 基于CGLIB代理形式实现: AOP相干术语:切面(aspect):个别为一个具体类(@Aspect注解正文)切入点() 告诉(Advice):在切面的某个特定点上执行的扩大 切入点(pointcut):应用@Pointcut注解进行切入点的形容,应用bean表达式定义切入点,语法:bean(spring容器中治理的某个bean的名字),bean表达式是一种粗粒度的切入点表达式(不能具体到bean中哪个办法)需写一个办法作为承载切入点 连接点(joinpoint):封装了切入点汇合办法中的某个正在执行的指标办法 AOP增加的依赖:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency> 注解阐明:@Aspect 注解用于标识或者形容AOP中的切面类型,基于切面类型构建的对象用于为指标对象进行性能扩大或控制目标对象的执行。@Pointcut注解用于形容切面中的办法,并定义切面中的切入点(基于特定表达式的形式进行形容),在本案例中切入点表达式用的是bean表达式,这个表达式以bean结尾,bean括号中的内容为一个spring治理的某个bean对象的名字。@Around注解用于形容切面中办法,这样的办法会被认为是一个盘绕告诉(外围业务办法执行之前和之后要执行的一个动作),@Aournd注解外部value属性的值为一个切入点表达式或者是切入点表达式的一个援用(这个援用为一个@PointCut注解形容的办法的办法名)。ProceedingJoinPoint类为一个连接点类型,此类型的对象用于封装要执行的指标方告诉类型(告诉-Advice形容的是一种扩大业务):1.@Before。(指标办法执行之前执行)2.@AfterReturning。(指标办法胜利完结时执行)3.@AfterThrowing。(指标办法异样完结时执行)4.@After。(指标办法完结时执行)5.@Around.(重点把握,指标办法执行前后都能够做业务拓展)(优先级最高) 阐明:在切面类中应用什么告诉,由业务决定,并不是说,在切面中要把所有告诉都写上。 切入点表达式加强:** bean表达式(重点) bean表达式个别利用于类级别,实现粗粒度的切入点定义,案例剖析: bean("userServiceImpl")指定一个userServiceImpl类中所有办法。bean("*ServiceImpl")指定所有后缀为ServiceImpl的类中所有办法。阐明:bean表达式外部的对象是由spring容器治理的一个bean对象,表达式外部的名字应该是spring容器中某个bean的name。 缺点:不能准确到具体方法,也不能针对于具体模块包中的办法做切入点设计 =========================================================== within表达式(理解) within表达式利用于类级别,实现粗粒度的切入点表达式定义,案例剖析: within("aop.service.UserServiceImpl")指定以后包中这个类外部的所有办法。within("aop.service.*") 指定当前目录下的所有类的所有办法。within("aop.service..*") 指定当前目录以及子目录中类的所有办法。within表达式利用场景剖析: 1)对所有业务bean都要进行性能加强,然而bean名字又没有规定。 2)按业务模块(不同包下的业务)对bean对象进行业务性能加强。 =========================================================== execution表达式(理解) execution表达式利用于办法级别,实现细粒度的切入点表达式定义,案例剖析: 语法:execution(返回值类型 包名.类名.办法名(参数列表))。 execution(void aop.service.UserServiceImpl.addUser())匹配addUser办法。execution(void aop.service.PersonServiceImpl.addUser(String)) 办法参数必须为String的addUser办法。execution( aop.service...*(..)) 万能配置。=========================================================== @annotation表达式(重点) @annotaion表达式利用于办法级别,实现细粒度的切入点表达式定义,案例剖析 @annotation(anno.RequiredLog) 匹配有此注解形容的办法。@annotation(anno.RequiredCache) 匹配有此注解形容的办法。其中:RequiredLog为咱们本人定义的注解,当咱们应用@RequiredLog注解润饰业务层办法时,零碎底层会在执行此办法时进行日扩大操作。 切面优先级设置实现切面的优先级须要借助@Order注解进行形容,数字越小优先级越高,默认优先级比拟低。列如:@Order(1),@Order(2)

November 12, 2020 · 1 min · jiezi

关于aop:Spring-AOP使用时的一些问题

在应用AOP的时候遇到了一些问题,特此记录一下 首先写一个罕用的AOP切片 切片类AopLogpackage com.mantis.aop.aspect;import com.fasterxml.jackson.databind.ObjectMapper;import com.mantis.aop.common.util.DataUtil;import eu.bitwalker.useragentutils.UserAgent;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import org.springframework.validation.BeanPropertyBindingResult;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.ArrayList;import java.util.Arrays;import java.util.Enumeration;import java.util.List;import java.util.stream.Collectors;/** * @Description:执行程序 失常程序 Around Before Method.invoke Around After AfterReturning * 异样程序 Around Before Method.invoke After AfterThrowing * @author: wei.wang * @since: 2020/4/4 13:47 * @history: 1.2020/4/4 created by wei.wang */@Aspect@Componentpublic class AopLog { private static Logger logger = LoggerFactory.getLogger(AopLog.class); /** * 定义切点,切点为com.smec.fin.controller包和子包里任意办法的执行和service层所有办法的执行 */ @Pointcut("execution(public * com.mantis.aop.controller..*.*(..))") public void log() { // 定义切点 } /** * 定义切点,切点为com.smec.fin.controller包和子包里任意办法的执行和service层所有办法的执行 */ @Pointcut("execution(public * com.mantis.aop.service.impl..*.*(..))") public void log2() { // 定义切点 } /** * 盘绕告诉 * * @param point * @return * @throws Throwable */ @Around("log2()") public Object aroundLog(ProceedingJoinPoint point) throws Throwable { logger.info("开始执行盘绕操作"); Object result = point.proceed(); logger.info("执行盘绕操作完结,返回值:{}", result); return result; }}服务类AopServiceImplpackage com.mantis.aop.service.impl;import com.mantis.aop.service.AopService;import org.springframework.aop.framework.AopContext;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;/** * @Description: * @author: wei.wang * @since: 2020/10/24 12:45 * @history: 1.2020/10/24 created by wei.wang */@Servicepublic class AopServiceImpl implements AopService { @Override public void testAop(String str) { System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testAop" + str); this.testAop2("testFinalMethod"); } @Override public void testAop2(String str) { //this.testFinalMethod("testFinalMethod"); System.out.println("com.mantis.aop.service.AopService.AopServiceImpl." + str); } public final void testFinalMethod(String str) { System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str); } public void testFinalMethod2(String str) { System.out.println("com.mantis.aop.service.AopService.AopServiceImpl.testFinalMethod" + str); }}1.同办法运行问题在应用AOP时咱们发现存在同类中调用时切点生效问题,在执行时咱们发现只执行了testAop的切点,testAop2的切点没有执行,这是因为通过AOP代理后的对象都曾经不是原来的对象了,而是退出了加强办法的代理对象,应用代理对象调用时能够执行加强办法,然而这里是应用this调用的,也就是AopServiceImpl,因为不是代理对象就没有加强办法。 ...

October 24, 2020 · 3 min · jiezi

关于aop:aop的注解和具体内容

应用jdk代理形式 AOP默认应用的CGLIB代理spring.aop.proxy-target-class=false<!-- Aop 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>@Aspect//注解用于示意或者形容aop中的切面类型 用于为指标对象进行性能扩大或控制目标对象的执行//由此注解形容的类为springaop 中的一个切面类型此类型能够定义//1切入点 (Pointcut)办法(能够是多个)要进行性能扩大的一些点//2告诉advice办法能够是多个封装了扩大性能的一些办法在切入点办法之前货之后要执行的办法@Slf4j//打印日志信息@Component//是spring形容bean类的一个注解 用于通知spring这个类的实例由spring创立public class SysLogAspect { //在业务层 的imp小写复制过去 @Pointcut("bean(sysUserServiceImpl)")//注解哟凝固形容切面中的办法 定义切面中的切入点 定义这个类所有切入办法 //本注解以bean结尾 bean括号中的内容为一个spring治理的某个bean对象的名字 // public void logPointCut() {}//办法中不写任何内容 只是切入点表达式的一个载体 //aournd注解外部value属性的值 为一个切入点表达式一个援用 这个援用为一个@pointcut注解示意的办法的办法名 //ProceedingJoinPoint类为一个连接点类型,此类型的对象用于封装要执行的指标办法 //他只能用于@Around注解形容的办法参数。 @Around("logPointCut()")//注解以用于形容切面中办法 会被认为是一个盘绕告诉 和型业务 执行之前个之后要执行的一个动作 public Object around(ProceedingJoinPoint jp)//指标办法 throws Throwable{ long t1=System.currentTimeMillis();//执行工夫 try { Object result=jp.proceed();//最终可能要执行你的指标办法 long t2=System.currentTimeMillis();//执行工夫 log.info("指标办法{}执行时长{}",t2-t1);//{}这个在log.info外面代表占位符 return result; }catch(Throwable e) { log.error("指标办法呈现了点问题具体为:{}",e.getMessage());//记录日志 throw e; } }}aop 异样解决监听@Slf4j@Aspect@Componentpublic class SysExceptionAspect { /**此办法能够作为一个异样监控办法*/ @AfterThrowing(pointcut = "bean(*ServiceImpl)",throwing = "ex") public void handleException(JoinPoint jp,Throwable ex) { //通过连接点获取指标对象类型 Class<?> targetClass=jp.getTarget().getClass(); String className=targetClass.getName(); //通过连接点获取办法签名对象 MethodSignature s=(MethodSignature)jp.getSignature(); String methodName=s.getName();//获取指标办法名 String targetClassMethod=className+"."+methodName; log.error("{}'exception msg is {}",targetClassMethod,ex.getMessage()); //拓展? //1)将日志写到日志文件 //2)将出现异常的这个信息发送到某个人的邮箱(email),例如QQ邮箱 //3)将出现异常的状况发短信给某人(运维人员) //4)报警(播放一段好听的音乐) }}

October 14, 2020 · 1 min · jiezi

关于aop:AOP形式实现Redis缓存

AOP连接点罕用APIProceedingJoinPoint只能盘绕告诉应用(ProceedingJoinPoint控制目标办法的执行),如果当做参数来用,必须位于参数的第一位 private void saveSysLog(ProceedingJoinPoint point){ //1.获取指标类(就相当于晓得了是哪一个类) Class<?> targetCls = point.getTarget().getClass(); MethodSignature ms= (MethodSignature) point.getSignature(); System.out.println("ms________________"+ms); String methodName = ms.getName();//再获取办法名 //2.获取类里的办法(类里有很多办法 通过办法名和办法参数类型可能确定是哪一个办法) Method targetMethod=targetCls.getMethod(methodName,ms.getParameterTypes()); //3.获取指标办法上的注解 RequiredLog requiredLog = targetMethod.getAnnotation(RequiredLog.class); //4.获取注解上的值if(requiredLog!=null){ operation=requiredLog.value();}String method=targetCls.getName()+"."+methodName; Object[] paramsObj=point.getArgs(); //转一般串 //String params= Arrays.toString(paramsObj); //将参数转换为字符串 String params=new ObjectMapper().writeValueAsString(paramsObj); }public void before(JoinPoint joinPoint){ //getSignature:获取是一个对象(外面蕴含办法的返回值 办法名 办法参数) String methodName = joinPoint.getSignature().getName(); String typeName = joinPoint.getSignature().getDeclaringTypeName(); System.out.println("指标办法的门路:"+typeName+"."+methodName); // getArgs:返回指标办法的参数 Object[] args = joinPoint.getArgs(); System.out.println("参数:"+ Arrays.toString(args)); Class<?> methodClass = joinPoint.getTarget().getClass(); System.out.println("指标对象类型:"+methodClass);入门案例@Aspect //我是一个aop的切面类@Component//将类交给spring容器治理public class CacheAOP { //公式=切入点表达式 + 告诉办法 /* *对于切入点表达式的应用阐明 * 粗粒度: * 1.bean(bean的Id)一个类 bean的Id指的是交给spring容易治理的类的类名小写 , * 也能够bean(*ServiceImpl) 多个类 * 2.within(包名.类名) 一个类/*代替就是多个 */ @Pointcut("bean(itemCatServiceImpl)") public void pointCut(){ //定义切入点表达式 只为了占位 } //定义前置告诉,与切入点表达式进行绑定,留神绑定的是办法 @Before("pointCut()") //等同于@Before("bean(itemCatServiceImpl") 区别:pointCut()示意切入点表达式的援用 //实用于多个告诉同用状况 public void before(JoinPoint joinPoint){ //getSignature:获取是一个对象(外面蕴含办法的返回值 办法名 办法参数) String methodName = joinPoint.getSignature().getName(); String typeName = joinPoint.getSignature().getDeclaringTypeName(); System.out.println("指标办法的门路:"+typeName+"."+methodName); // getArgs:返回指标办法的参数 Object[] args = joinPoint.getArgs(); System.out.println("参数:"+ Arrays.toString(args)); Class<?> methodClass = joinPoint.getTarget().getClass(); System.out.println("指标对象类型:"+methodClass); System.out.println("我是前置告诉"); } @Around("pointCut()")public Object doaround(ProceedingJoinPoint joinPoint) { /** * ProceedingJoinPoint只能盘绕告诉应用(ProceedingJoinPoint控制目标办法的执行), * 如果当做参数来用,必须位于参数的第一位, */ Object result=null; try { result = joinPoint.proceed();//执行下一个告诉或指标办法 } catch (Throwable throwable) { throwable.printStackTrace(); } System.out.println("盘绕告诉完结"); return result;} }AOP 实现 Redis缓存编写配置类 ...

October 14, 2020 · 2 min · jiezi

关于aop:AOP编程全解析

AOP是一种编程思维,一套标准。 软件开发经验了面向过程编程时代,以C语言为代表,之后是面向对象编程时代,以Java语言为代表。 在21世纪大牛们又提出了一种新的编程思维面向方面编程,即AOP理念,全称Aspect-Oriented Programming。 AOP是第三代编程思维,到哪免不了都要问下。倒退历史1997年在面向对象编程大会上Gregor Kiczales等人首次提出了AOP的概念,之后各大公司等别离退出钻研。2001年Palo Alto钻研核心公布了首个反对AOP的语言AspectJ,同时也是一个标准。 指标定位在对真实世界形象的面向对象编程过程中,始终随同着某写操作的代码无奈实现模块化封装,会散落在各个对象中存在,特地是非功能性代码。对于个别的性能开发采取面向对象形式进行形象是可能很好应酬的,然而面向方面(切面)给了一种新的思维形式来思考编程,能更好的进行全局结构化思考。 所以AOP次要解决两个问题: 代码扩散问题,特地是那些非功能性代码。作为面向对象编程思维的一种补充和欠缺。 外围知识点连接点连接点:join point,程序的一个执行点,如类中的一个办法,办法外面一个代码块。 切入点切入点:point cut,是一个捕捉连接点的代码构造,就是定义一个代码逻辑用来捕捉某个连接点的代码。 方面方面;aspect,是具体被执行的切面逻辑代码,相似于一个类。 告诉告诉:advice,是point cut执行的代码,定义在连接点什么机会来执行aspect。 次要使用场景场景分为2类: 一类是非功能性需要,如日志、异样、平安、事务都能够应用AOP思维编程。 另一类是功能性需要,在原来对象形象的思维中增加AOP思维,这里是一种结构化思维,在定义类时思考多个类的切面共性。 支流AOP语言实现对AOP实现除了AspectJ外,已知的还有JBoss AOP、Spring AOP等。 这里只介绍AspectJ和SpringAOP,重点是他们不同点。AspcetJAspectJ采纳动态织入形式进行切面织入原代码,提供独立的编译器把切面和原代码的java文件编织成一个新的class文件。提供了具体的编译日志和调试工具,编译工夫长然而运行效率高。 连接点的反对范畴: 办法和结构器调用办法和结构器执行属性拜访异样解决类初始化,是static代码块语法结构控制流对象及参数类型条件测试关联连接点告诉形式: before,连接点执行前运行after,连接点执行后运行around,连接点的整个外侧,整个包住,可能绝的连接点执行和批改上下文环境Spring AOPSpring AOP没有齐全实现AspectJ语言,它更多的是对Spring framwork进行Aop能力的扩大实现,补全Spring framework的有余并让Aop与Spring framwork交融。 连接点只反对办法拦挡调用。 连接点告诉形式在aspect的before、after、around的根底上减少throw对异样的触发的拦挡。 Spring AOP与Spring IoC体系交融,对于aspect类对立交由Spring beans治理,并且提供ProxyFactoryBean的AOP代理工厂类,还有主动代理的BeanNameAutoProxyCreator和DefaultAdvisorAutoProxyCreator的弱小工具。 Spring AOP是动静织入,在运行时实现AOP的aspect代码织入原代码逻辑中。其底层默认采纳JDK的动静代理实现AOP代理,当对象没有实现接口时,CGLIB会默认应用。 优缺点长处:解决代码散乱问题、代码逻辑解偶、易于保护、提供扩展性和可重用性。 毛病:切面越多零碎越简单难懂、工程师学习成本增加(业务不再是线型,变成了跳跃式) AOP编程要谨慎应用,作为面向对象编程的一种补充。 作者:Owen Jia 关注他的博客:https://blog.shareworld.vip

September 28, 2020 · 1 min · jiezi

关于aop:Spring中基于AOP的事务管理

Spring中基于AOP的事务管理1.在我的项目启动类上增加@EnableTransactionManagement注解,(新版本springboot不必增加)2.在适合的类上或者办法上增加@Transactional注解 @Transcationl当在一个业务的办法中设置一个异样时,尽管抛出了异样,然而数据还是变动了!!当状态从0禁止变为1(启用)时我在下面设置了抛出一个异样刷新页面后,发现数据曾经产生了变动!!当我在用户业务层增加 @Transactionl后数据产生了回滚,禁止并没有变成启动!阐明transcationl失效了 readyOnly readyOnly只读:指定事务是否是只读事务当在用户的业务层上注解@Transactional(readOnly = true)如果再对用户进行增删改等操作时,就会报错 当readOnly只读默认是false,在进行查问的时候应用true能够减少效率,然而对于增删改等要应用true rollbackFor rollbackFor:在呈现指定异样时回滚(默认RuntimeException,Error都会滚) 在扭转状态的业务办法上增加rollbackFor属性,值为自定义异样;在valid==1时,抛出此异样;检测数据是否回滚能够看到抛出异样,并且禁用状态并没有扭转,数据回滚了 noRollbackFor noRollbackFor:呈现指定异样,不产生回滚 把之前的rollbackFor改为noRollbackFor扭转状态,扭转之前是禁用抛出异样后刷新页面,状态曾经变成启用了。阐明尽管应用@Transactional注解,抛出了异样,然而数据并没有回滚 timeout 超出设定工夫业务没有实现就回滚 isolation 事务隔离级别 如果多个事务并行执行,就会呈现脏读、幻读、反复读等景象,如果不心愿呈现这种景象,就能够设置此属性,个别设置值为 : Isolation.READ_COMMITTEDpropagation 事务的流传个性 **不同业务对象(service)**中事务办法之间互相调用时,业务的传播方式。 默认是:Propagation.REQUIRES_NEW 。指多个事务之间是同一个事务对象,其中一个事务回滚,之前的事务都会回滚 如果想让其中一个事务回滚时,其余事务不回滚;就应用 Propagation.REQUIRES_NEW

September 19, 2020 · 1 min · jiezi

关于aop:AOP基础1

Spring AOP1.什么是AOP? AOP是一种面向切面的编程思维,是OOP的一种扩大和补充;和OOP(面向对象)相比,是一种动静过程;AOP,它可能在预编译阶段和运行期动静代理的形式,实现在不批改代码的状况下给程序增加额定的性能。 AOP常被用在非核心业务的扩大上,进步零碎的可扩展性。例如日志治理,权限治理,事务处理,缓存等。2.CGLIB(默认),JDK AOP的底层是基于动静代理实现的 (1)如果被代理对象实现的是接口,就能够应用JDK动静代理机制对指标创立代理对象(代理对象和被代理对象实现同一个接口) (2)如果被代理对象没有实现接口,就能够应用CGLIB代理机制创立代理对象(代理对象implemens被代理对象) (3)应用JDK时须要配置文件中:spring.aop.proxy-target-class=false3.AOP相干术语 (1)Aspect:定义一个切面类,被此注解形容的类是一个Spring AOP的一个切面类 (2)PointCut:定义一个切入点办法;只能存在Aspect中;属性值是切入点的切入点表达式,有多种;切入点是连接点的汇合; (3)Joinpoit:程序执行中的连接点,个别指向被拦挡到的指标办法 (4)Advice:定义一个告诉,及切入点要执行的办法;其属性值是切入点表达式 4.切入点表达式4.1 bean:用于匹配bean对象的所有办法 bean表达式个别用于类级别,实现粗粒度的切入比方: bean(userServiceImpl) 指定userServiceImpl中的所有办法 bean(*ServiceImpl) 指定以ServiceImpl结尾的所有类的所有办法 4.2 annotation: @annotation是办法级别的细粒度切入办法,比方: ("@annotation(com.com.py.pj.common.annotation.SysLogRequired)") 其中com.com.py.pj.common.annotation是创立注解的包;SysLogRequired是注解名 应用此接入点表达式时,须要把自定义的注解写在业务办法上。 5.须要的依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency>6.代码实现参考 AOP之记录用户日志行为

September 18, 2020 · 1 min · jiezi

关于aop:AOP之记录用户日志行为

Aop之输入日志保留在数据库中 1.须要的依赖 <dependencies> <!-- AOP依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies>2.切面类和注解 package com.py.pj.common.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * @author WL * @version 创立工夫:2020-9-17 19:10:00 * @Description 保留日志自定义注解 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface SysLogRequired { String value();}package com.py.pj.common.aspect;import java.lang.reflect.Method;import java.util.Date;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import com.py.pj.common.annotation.SysLogRequired;import com.py.pj.sys.entity.SysLog;import com.py.pj.sys.service.SysLogService;/*** @author WL* @version 创立工夫:2020-9-17 19:11:17* @Description 切面类;实现日志的主动保留*/@Aspect@Componentpublic class SysLogAspect { private static final Logger log = LoggerFactory.getLogger(SysLogAspect.class); @Autowired private SysLogService sysLogService; // 切入点;应用@annotation的形式,细粒度 @Pointcut("@annotation(com.py.pj.common.annotation.SysLogRequired)") public void doSaveLog() {} // 盘绕告诉; @Around("doSaveLog()") public Object around(ProceedingJoinPoint jp) throws Throwable{ long t1 = System.currentTimeMillis(); Object result = jp.proceed(); // 要执行的办法 long t2 = System.currentTimeMillis(); long t = t2-t1; log.info("执行工夫:{ }",t); SaveLog(jp,t); return result; } /** * @param jp * @param time * getSignature(): 该办法次要获取被代理对象的属性名称汇合 * getTarget():此处是取得了被代理类的对象Impl * @throws JsonProcessingException * @throws SecurityException * @throws NoSuchMethodException */ private void SaveLog(ProceedingJoinPoint jp, long time) throws JsonProcessingException, NoSuchMethodException, SecurityException { //List com.py.pj.sys.serviceImpl.SysDeptServiceImpl.findObjects() MethodSignature ms = (MethodSignature) jp.getSignature(); //....办法全类名 System.out.println("ms="+ms); Class<?> targetClass = jp.getTarget().getClass(); // 被代理的类的反射 String targetName = targetClass.getName(); //DaoImpl被代理的类对象的名字 System.out.println("targetName="+targetName);//com.py.pj.sys.serviceImpl.SysDeptServiceImpl // 获取接口申明办法 String MethodName = ms.getMethod().getName();//findObjects System.out.println("MethodName="+MethodName); Class<?>[] parameterTypes = ms.getMethod().getParameterTypes(); // 暴力反射获取办法 Method targetMethod = targetClass.getDeclaredMethod(MethodName, parameterTypes); //获取办法参数 Object[] paramObj = jp.getArgs(); System.out.println("paramObj="+paramObj); String params = new ObjectMapper().writeValueAsString(paramObj); String username = "weilong"; SysLog slog = new SysLog(); SysLogRequired operation = targetMethod.getDeclaredAnnotation(SysLogRequired.class); if (targetMethod!=null) { slog.setOperation(operation.value()); } slog.setCreatedTime(new Date()); slog.setIp("1.1.1.1"); slog.setMethod(targetName+"."+MethodName); slog.setParams(params); slog.setUsername(username); slog.setTime(time); sysLogService.insertObjects(slog); }}3.在须要增加日志的业务办法上增加正文 ...

September 18, 2020 · 2 min · jiezi

关于aop:Spring-Aop

一,AOP术语阐明1,告诉Advice:在AOP中,切面的工作被称为告诉。告诉定义了切面“是什么”以及“何时”应用。除了形容切面要实现的工作,告诉还解决了何时执行这个工作的问题。Spring切面能够利用5中类型的告诉:`(1)前置告诉(Before):前置告诉,在办法执行之前执行;(2)后置告诉(After):后置告诉,在办法执行之后执行;(3)返回告诉(After-returning):返回告诉,在办法返回后果之后执行;(4)异样告诉(After-throwing):异样告诉,在办法抛出异样之后执行;(5)盘绕告诉(Around):盘绕告诉,围绕着办法执行; ` 2,连接点(Join point):连接点是在利用执行过程中可能插入切面的一个点。这个点能够是调用办法时,抛出异样时,甚至是批改一个字段时。切面代码能够利用这些点插入到利用的失常流程之中,并增加行为。 3,切点(Pointcut):如果说告诉定义了切面“是什么”和“何时”的话,那么切点就定义了“何处”。比方我想把日志引入到某个具体的办法中,这个办法就是所谓的切点。 4,切面(Aspect):切面是告诉和切点的联合。告诉和切点独特定义了切面的全部内容————它是什么,在何时和何处实现其性能。 三、应用基于注解的形式实现AOP1.须要引入相干的jar,应用maven` com.springsource.net.sf.cglib-2.2.0.jar com.springsource.org.aopalliance-1.0.0.jar com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar spring-aspects-4.0.0.RELEASE.jar` 2、在Spring的配置文件中退出 aop 的命名空间3、须要在Spring的配置文件中,退出如下配置:<!-- 主动扫描的包 --> <context:component-scan base-package="com.scorpios.spring.aop.impl"></context:component-scan> <!-- 使 AspectJ 的注解起作用 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy>组件扫描(component scanning):Spring 可能从classpath下主动扫描, 侦测和实例化具备特定注解的组件。 特定组件包含: @Component: 根本注解, 标识了一个受Spring治理的组件 @Respository: 标识长久层组件 @Service: 标识服务层(业务层)组件 @Controller: 标识体现层组件对于扫描到的组件, Spring有默认的命名策略: 应用非限定类名, 第一个字母小写。 也能够在注解中通过value属性值标识组件的名称 3、编写业务办法接口public interface ArithmeticCalculator { int add(int i,int j); int sub(int i,int j); int mul(int i, int j); int div(int i, int j); }4、实现业务办法 (留神此处Component注解)@Componentpublic class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { int result = i + j; return result; } @Override public int sub(int i, int j) { int result = i - j; return result; } @Override public int mul(int i, int j) { int result = i * j; return result; } @Override public int div(int i, int j) { int result = i / j; return result; }}5、 编写切面类:(是个别的Java类,在其中增加要额定实现的性能,留神注解)

September 17, 2020 · 1 min · jiezi

关于aop:4-Spring-AOP事务管理

1 Spring中AOP事务简介1.1 事务事务(Transaction)是一个业务,是一个不可分割的逻辑工作单元,基于事务能够更好的保障业务的正确性。 1.2 事务个性: (ACID个性)原子性(Atomicity):一个事务中的多个操~~~~作要么都胜利要么都失败一致性(Consistency): 操作前后总数应该是统一的。隔离性(Isolation):事务与事务之间是互相隔离的持久性(Durability):事务一旦提交数据会长久保留到数据库 2 Spring中事务管理2.1spring中事务形式概述Spring框架中提供了一种申明式事务的解决形式,此形式基于AOP代理,能够将具体业务逻辑与事务处理进行解耦。也就是让咱们的业务代码逻辑不受净化或大量净化,就能够实现事务管制。 在SpringBoot我的项目中,其外部提供了事务的主动配置,当咱们在我的项目中增加了指定依赖spring-boot-starter-jdbc时,框架会主动为咱们的我的项目注入事务管理器对象,最罕用的为DataSourceTransactionManager对象。 2.2理论我的项目中最罕用的注解形式的事务管理基于@Transactional 注解进行申明式事务管理的实现步骤1) 启用申明式事务管理,在我的项目启动类上增加@EnableTransactionManagement,咱们新版本中也可不增加(例如新版Spring Boot我的项目)。 2) 将@Transactional注解增加到适合的业务类或办法上,并设置适合的属性信息。 2.3 AOP 编程中基于注解形式的事务管制@Transactional2.3.1@Transactional形容类示意类中所有办法都要进行事务管制,如果办法上也有该注解则办法上的事务注解个性优先级比拟高2.3.2 readOnly属性 含意:是否为只读事务(只容许查问操作 其余操作不容许) 默认值是false。readOnly=false所注解的办法或类代表减少,删除,批改业务.readOnly=true代表读取数据2.3.3 rollbackFor属性含意是(什么异样回滚事务) 默认值是(RuntimeException与Error 呈现这俩个都会回滚事务 然而查看异样(IllegalAccessException)不回滚)2.3.4 noRollbackFor属性 含意是什么(什么状况下不回滚),没有默认值2.3.5 timeout 属性含意为是否反对事务超时,默认没有值,若为-1默认不反对事务超时,咱们能够定义超时工夫。如果配置了具体工夫,则超过该工夫限度但事务还没有实现,则主动回滚事务。这个工夫的记录形式是在事务开启当前到sql语句执行之前。2.3.6 isolation=Isolation.READ_COMMITTED (默认写成它就行 不呈现脏读),把事务隔离级别设置为它,不容许呈现脏读(事务隔离级别较低)。隔离级别越高并发就会越小,性能越差,但更平安。 事务管制过程剖析Spring事务管理是基于接口代理(JDK)或动静字节码(CGLIB)技术,而后通过AOP施行事务加强的。当咱们执行增加了事务个性的指标形式时,零碎会通过指标对象的代理对象调用DataSourceTransactionManager对象,在事务开始的时,执行doBegin办法,事务完结时执行doCommit或doRollback办法。 3 Spring 中事务流传个性事务流传(Propagation)个性指"不同业务(service)对象"中的事务办法之间互相调用时,事务的传播方式。 3.1罕用事务传播方式3.1.1@Transactional(propagation=Propagation.REQUIRED)如果没有事务创立新事务, 如果以后有事务参加以后事务, Spring 默认的事务流传行为是PROPAGATION_REQUIRED,它适宜于绝大多数的状况。 //代码示例@Transactional(propagation = Propagation.REQUIRED) @Override public List<Node> findZtreeMenuNodes() { return sysMenuDao.findZtreeMenuNodes(); }当有一个业务对象调用如上办法时,此办法始终工作在一个曾经存在的事务办法,或者是由调用者创立的一个事务办法中。3.1.2@Transactional(propagation=Propagation.REQUIRES_NEW)必须是新事务, 如果有以后事务, 挂起以后事务并且开启新事务。 //代码示例@Transactional(propagation = Propagation.REQUIRES_NEW) @Override public void saveObject(SysLog entity) { sysLogDao.insertObject(entity); }当有一个业务对象调用如上业务办法时,此办法会始终运行在一个新的事务中。 ...

September 17, 2020 · 1 min · jiezi

关于aop:Spring-AOP

什么是AOPAOP(Aspect Orient Programming)是一种设计思维,是软件设计畛域中的面向切面编程,是面向对象编程(OOP)的一种补充和欠缺。它以通过预编译形式和运行期动静代理形式,实现在不扭转源代码的状况下给程序动静对立增加额定性能的一种技术。能够说AOP是OOP动静的一部分,OOP是一种动态,必须想确定好对象、子系统、模块(少返工)...AOP面向切面的运行代理,能够对象运行时动静的织入一些扩大性能或管制对象执行。{(服务增益)基于根本业务,做日志解决、权限管制、事务处理、做异步、做缓存......} 补充:设计思维:MVC分层架构设计思维、连接池(池化思维)、IOC管制反转思维、面向对象(OOP)....... OCP:开闭准则,实现性能的扩大业务在AOP编程时,如何基于OCP准则实现性能扩大? 1.在编译时,相似于用Lomback思维,在编译时主动重写。 2.在运行时,对这个办法重写(写一个子类继承这个类重写)或组合形式:对象之间的协同 Spring AOP利用原理剖析基于代理机制机制(动静形式)实现性能扩大1.JDK动静代理机制:指标对象(被代理对象)实现接口,JDK代理机制为指标对象创立代理对象(指标类和代理类会实现独特接口)----了解为兄弟关系,兄弟间协同、耦合2.CGLIB代理机制:指标对象(被代理对象)没有实现接口,CGLIB代理机制为指标对象创建对象(默认创立的代理类会继承指标对象类型)----继承----SpringBoot2.X中AOP默认应用CGLIB代理,如果要应用JDK代理能够在配置文件(applicatiion.properties)**中进行配置:spring.aop.proxy-target-class=false Spring中AOP相干术语1.切面(aspect):横切面对象,借助@Aspect申明2.告诉(Advice):在切面的某个特定的连接点上执行的动作(扩大性能)3.连接点(joinpoint):程序执行过程中某个特定的点,个别指拦挡到的指标办法4.切入点(pointput):对多个连接点的一种定义,个别能够了解为多个连接点的汇合@Aspect注解用于标识或者形容AOP中的切面类型,基于切面类型构建的对象用于为指标对象进行性能扩大或控制目标对象的执行。@PointCut注解用于形容切面中的办法,并定义切面中的切入点(基于特定表达式的形式进行形容)@Around注解用于形容切面种办法,这样的办法会被认为是一个盘绕告诉(外围业务执行之前和之后要执行的一个动作),@Aournd注解外部value属性的值为一个切入点表达式或者是切入点表达式的一个援用(这个援用为一个@PointCut注解形容的办法的办法名)。ProceedingJoinPoint类为一个连接点类型,此类型的对象用于封装要执行的指标办法相干的一些信息。只能用于@Around注解形容的办法参数。

September 16, 2020 · 1 min · jiezi

关于aop:缓存服务器Redis-04-AOP实现Redis缓存服务

在上文中,咱们尽管在业务层service中实现了代码的实现.然而该代码不具备复用性.如果换了其余的业务则须要从新编辑. 并且因为缓存的代码写在业务层service中,所以代码的耦合性高,不不便当前的扩大. 所以咱们从代码复用以及升高代码的耦合性的方面应用AOP来实现redis缓存. AOPAOP即面向切面编程--在不改变原有代码的根底上,对业务进行加强. AOP = 切入点表达式 + 告诉办法 专业术语: 1.连接点: 在执行失常的业务过程中满足了切入点表达式时进入切面的点.(织入) 多个 2.告诉: 在切面中执行的具体的业务(扩大) 办法 3.切入点: 可能进入切面的一个判断 if判断 一个 4.指标办法: 将要执行的实在的业务逻辑. 告诉办法分类:1.前置告诉(@Before): 指标办法执行之前执行 2.后置告诉(@After): 指标办法执行之后执行 3.异样告诉(@AfterThrowing): 指标办法执行之后抛出异样时执行 4.最终告诉(@AfterReturning): 不论什么时候都要执行的办法. 阐明:上述的四大告诉类型不能控制目标办法是否执行.个别应用上述的四大告诉类型,都是用来记录程序的执行状态.5.盘绕告诉(@Around): 在指标办法执行前后都要执行的告诉办法. 控制目标办法是否执行.并且盘绕告诉的性能最为弱小.盘绕告诉是最为罕用的. 切入点表达式分类:1.bean(bean的id) 类名首字母小写 匹配1个类 2.within(包名.类名) 按包门路匹配类 匹配多个类 上述表达式是粗粒度的管制,按类匹配. 3.execution(返回值类型 包名.类名.办法名(参数列表)) 4.@annotation(包名.注解名) 按注解进行拦挡.上述是细粒度的管制.bean和@annotation较为罕用 实现Redis缓存业务剖析1.自定义注解CacheFind 次要被注解标识的办法,则开启缓存的实现. 2.为了未来辨别业务,须要在注解中标识key属性,由使用者自行填写. 3.为了用户提供数据超时性能. 自定义注解@CacheFind@Retention(RetentionPolicy.RUNTIME) //该注解运行时无效@Target({ElementType.METHOD}) //对办法无效public @interface CacheFind { String key(); //该属性为必须增加 int seconds() default 0; //设定超时工夫 默认不超时}编写CacheAOP类package com.jt.aop; import com.jt.annotation.CacheFind; import com.jt.util.ObjectMapperUtil; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import redis.clients.jedis.Jedis; import java.util.Arrays; @Component @Aspect public class RedisAOP { //注入缓存reids对象 @Autowired private Jedis jedis; //@Pointcut("@annotation(com.jt.annotation.CacheFind)") //public void doRedisPointCut(){} /** * 拦挡@CacheFind注解示意的办法 * 告诉抉择: 缓存的实现应该选用盘绕告诉 * 步骤: * 1.动静生成key 用户填写的key+用户提交的参数 */ @Around("@annotation(cacheFind)") public Object around(ProceedingJoinPoint joinPoint, CacheFind cacheFind){ try { Object result = null; //1.如何动静获取用户在注解中填写的数据 String prekey = cacheFind.key(); //2.动静获取指标办法中的参数 将数组转化为字符串 String args = Arrays.toString(joinPoint.getArgs()); String key = prekey + "::" + args; //"ITEM_CAT_PARENTID::[0]" //3.查问缓存中查问 //4.判断json中是否有值 if (jedis.exists(key)) { //先获取json数据 String json = jedis.get(key); //动静获取指标办法的返回值类型?? 向上造型 不必强转 向下造型 MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Class target = methodSignature.getReturnType(); //7.进入代表程序中有值,将json转为对象 result = ObjectMapperUtil.toObject(json, target); System.out.println("AOP实现缓存查问!!!!"); }else { //5.若缓存中没有查询数据库 result = joinPoint.proceed(); //执行指标办法,获取返回值后果 System.out.println("AOP执行数据库操作"); //6.将数据存到redis中 //先转为json格局 String json = ObjectMapperUtil.toJSON(result); if(cacheFind.seconds()>0){ //判断是否须要超时工夫 jedis.setex(key, cacheFind.seconds(), json); }else { jedis.set(key, json); } } return result; }catch (Throwable e){ e.printStackTrace(); throw new RuntimeException(e); } } }留神对于盘绕告诉参数的阐明:1.连接点必须位于告诉办法参数的第一位2.其余四大告诉类型不能够增加ProceedingJoinPoint对象,能够增加JointPoint对象 ...

September 11, 2020 · 2 min · jiezi

关于aop:全局异常的处理机制

作用在我的项目中,可能会遇到各种各样的异常情况,如果在每个办法中都增加其异样解决机制(如:trycatch),就会导致整个代码的构造都显得很凌乱;即便未来呈现了异样,解决起来也很麻烦,不能很好的治理,所以就须要将这些异样及逆行对立的形式进行异样解决. 实现@RestControllerAdvice //作用: 标识我是一个告诉办法,并且只拦挡Controll层的异样.并且返回JSON.public class SysResultException { //须要定义一个全局的办法 返回指定的报错信息. //ExceptionHandler 配置异样的类型,当遇到了某种异样时在执行该办法. @ExceptionHandler(RuntimeException.class) public Object exception(Exception e){ e.printStackTrace(); //日志记录/控制台输入. 让程序员晓得哪里报错!!! return SysResult.fail(); }}@RestControllerAdvice注解的作用:标识为一个告诉办法,并且只拦挡Controller层的异样.并且返回为JSON串.@ExceptionHandler(RuntimeException.class)注解的作用:配置异样的类型,当遇到了某种异样时在执行该办法,(RuntimeException.class)指异样类型为运行时异样. 留神因为我的项目中个别都是controller--service--mapper,所以咱们只须要在controller层进行对立异样解决即可,因为service/mapper层的异样都会往上抛出至controller层全局异样解决机制,该性能是通过Spring利用AOP实现的.

August 31, 2020 · 1 min · jiezi

关于aop:aop理解

Aop 了解什么是Aop?Aop是spring框架提供的切面编程,次要作用与在不批改原有业务的时候扩大新的业务.升高程序的耦合度,加强程序的开发效率.代码失去重用性. Aop如何实现Aop实现次要有两种形式配置中如果没有配置那么默认应用的是cglib1.jdk自代的动静代理.为指标对象创立代理对象2.cglib代理机制,为指标创立代理对象 什么是OCP准则(开闭准则)?ocp开闭准则是对业务批改敞开,对业务扩大开发 AOP 相干术语剖析@Async 进行异步操作spring框架会在底层创立一个新的线程池,被@Async润饰的办法会又线程池调配的一个线程来进行调用.@Order 设置优先级,设置数字优先级越高优先级也就越高 五大告诉@Advice 告诉.在切面的某一个链接点进行告诉操作例如:1.@befor:第二程序执行不论失 前置告诉2.@Around:优先级最高 盘绕告诉3.@After:不论程序执行胜利与否当快要执行完时都会先执行 后置告诉4.@AfterReturning: 程序执行胜利执行 返回告诉5.@Afterthwing: 程序执行失败执行 异样告诉 四大连接点@poincut 切面编程的切入点~~~~1.bean(间接指定保留在bean中的对象)粗略的切入点,该类下所有的办法都能够进行办法的扩大2.@annotation(指定注解接口的全限定类名),细腻的切入点,只有被该注解润饰的办法才会有办法的扩大3.within 用于匹配包下的所有类中的所有办法4.execution 用于指定办法~~~~ Spring AOP事务处理@Transaction默认事务回滚@Transaction(timeout:时长到时主动回滚事务) 如何获取注解上的值//1.获取用户行为日志信息 //获取指标对象(要执行的那个指标业务对象)类 Class<?> getcls = jp.getTarget().getClass(); MethodSignature sim = (MethodSignature) jp.getSignature();//强转是为了让他获取更多的办法 Method methods = getcls.getDeclaredMethod(sim.getName(), sim.getParameterTypes()); System.out.println(methods); //判断是否是LoginObject的注解值 LoginObject falg = methods.getAnnotation(LoginObject.class); String operation="operation"; if(falg!=null) operation = falg.value();盘绕告诉最为重要,重点一下由@Around注解形容的办法为一个盘绕告诉办法,咱们能够在此办法外部 手动调用指标办法(通过连接点对象ProceedingJoinPoint的proceed办法进行调用) 盘绕告诉:此盘绕告诉应用的切入点为bean(sysUserServiceImpl) 盘绕告诉特点: 1)编写: a)办法的返回值为Object. b)办法参数为ProceedingJoinPoint类型. c)办法抛出异样为throwable. 2)利用: a)指标办法执行之前或之后都能够进行性能拓展 b)绝对于其它告诉优先级最高。 @param jp 为一个连贯对象(封装了正在要执行的指标办法信息) @return 指标办法的执行后果 @throws Throwable 事务Transaction的解决@Transactional(timeout = 30, //执行时长到时主动回滚 readOnly = false, //只读事务,* 为了疏忽那些不须要事务的办法,比方读取数据,能够设置 read-only 为 true。 isolation = Isolation.READ\_COMMITTED,//事务的隔离级别,默认值采纳 DEFAULT. rollbackFor = Throwable.class, //异样回滚事务 propagation = Propagation.REQUIRED) //Propagation.new的话为事务的都在新的线程处理事务 no-rollback- for  抛出 no-rollback-for 指定的异样类型,不回滚事务。Spring 中事务流传个性@Transactional(propagation=Propagation.REQUIRED) 如果没有事务创立新事务, 如果以后有事务参加以后事务, Spring 默认的事务流传行为是PROPAGATION\_REQUIRED,它适宜于绝大多数的状况@Transactional(propagation=Propagation.REQUIRES\_NEW)必须是新事务, 如果有以后事务, 挂起以后事务并且开启新事务Spring AOP异步操作实现1. @EnableAsync //spring容器启动时会创立线程池 @SpringBootApplication public class Application { public static void main(String\[\] args) { SpringApplication.run(Application.class, args); }}2. @在须要异步执行的业务办法上,应用@Async办法进行异步申明。即可##### 当咱们须要本人对spring框架提供的连接池进行一些繁难配置,spring: task: execution: pool: queue-capacity: 128 阻塞队列最大期待线程数 core-size: 5 外围线程数 max-size: 128 最大线程数 keep-alive: 60000 当线程闲暇时60s后执行线程销毁回收 thread-name-prefix: db-service-task- 为线程创立名字Spring AOP中Cache操作实现1. @EnableCaching //spring容器启动时会主动启动cache配置缓存 @SpringBootApplication public class Application { public static void main(String\[\] args) { SpringApplication.run(Application.class, args); }}2.在须要缓存的办法上配置@Cacheable(value = "deptCache"), cache配置姓名以便前期清理缓存3.在须要清理缓存的办法上配置@CacheEvict(value="deptCache",allEntries=true)当执行完结的清理缓存,cache姓名和清理所以缓存配置在Spring中默认cache底层实现是一个Map对象,假如此map对象不能满足咱们理论须要,在理论我的项目中咱们能够将数据存储到第三方缓存零碎中. ...

August 22, 2020 · 1 min · jiezi

关于aop:Spring-AOP-01

概述AOP是spring框架中重要的一环,全称:Aspect Orient Programming,AOP是一种设计思维,意为面向切面编程,它是面向对象编程(OOP)的一种补充和欠缺.它以通过预编译形式和运行期动静代理形式两种形式实现在不批改源代码的状况下给程序动静对立增加额定性能的一种技术. oop与aop两者的区别能够了解为:oop是动态固定的,有多少模块多少对象,怎么执行都是运行前写好的;aop是动静扩大的,能够在对象运行时去如果一些扩大的性能或是管制对象执行某些性能. 利用场景我的项目中个别有外围业务与非核心业务,而非核心业务个别通过特定形式切入零碎-->个别就是借助于aop来实现. aop次要基于ocp(开闭准则)--对扩大凋谢,对批改敞开--简略来说就是增加性能时,不能扭转原有外围业务代码,只能在其上增加. aop能够实现,如:日志解决/事务处理/缓存解决等等. 原理剖析AOP底层基于代理机制实现性能扩大,有两种实现形式:1) 如果指标对象(被代理对象)实现接口,则底层能够采纳JDK动静代理机制为指标对象创立代理对象(指标类和代理类会实现独特接口2) 如果指标对象(被代理对象)没有实现接口,则底层能够采纳CGLIB代理机制为指标对象创立代理对象(默认创立的代理类会继承指标对象类型) Spring boot2.x当前的版本中AOP当初默认应用的CGLIB代理,如果须要应用JDK动静代理能够在配置文件(applicatiion.properties)中进行如下配置: spring.aop.proxy-target-class=false相干术语1) 切面(aspect): 横切面对象,个别为一个具体类对象(能够借助@Aspect申明)---AOP对象2) 告诉(Advice):在切面的某个特定连接点上执行的动作(扩大性能),例如around,before,after等---AOP办法3) 连接点(joinpoint):程序执行过程中某个特定的点,个别指被拦挡到的的办法---指标办法4) 切入点(pointcut):对多个连接点(Joinpoint)一种定义,个别能够了解为多个连接点的汇合---指标办法汇合 利用实例切面(aspect)@Aspect 注解形容的类为spring容器的一个切面对象类(此类型中封装切入点与告诉办法) 1)切入点:要执行拓展业务的办法的汇合2)告诉办法:封装了在切入点办法上要执行的拓展业务办法 切入点@Pointcut 注解用于形容切入点(在那些点上执行拓展业务) bean(bean类型名字):为一种切入点表达式(这个表达式中定义了那些bean对象的办法要进行性能拓展)例如:bean(sysUserServiceImpl)示意名字为sysUserServiceImpl的bean对象中所有办法的汇合为切入点,也就是说sysUserServiceImpl对象中任意办法执行时都要进行性能扩大 告诉办法@Around 注解形容的办法为一个告诉办法(服务增益办法),此办法外部能够做服务增益(拓展业务)@Around 注解外部要指定切入点表达式,在此切入点表达式对应的切入点办法上做性能扩大@param jp 示意连接点,是动静确定的,用于封装正在执行的切入点办法信息@return 指标办法的执行后果@throws Throwable 告诉办法执行过程中呈现的异样 ProceedingJoinPoint类为一个连接点类型,此类型的对象用于封装要执行的指标办法相干的一些信息。只能用于@Around注解形容的办法参数 //执行指标办法Object result = jp.proceed();//最终会调用指标办法(两头可能会其余告诉办法)加强切面告诉切面告诉共有五种:@Before/@AfterReturning/@AfterThrowing/@After/@Around(优先级最高)留神:切面并不是所有告诉都要应用,应用什么告诉由业务决定. 五个告诉的执行程序如下:@Around-->@Before-->指标办法-->@Around-->@After-->@AfterReturning(失常状况)/@AfterThrowing(异常情况) 切入点表达式1) bean:用于匹配指定bean对象的所有办法bean(bean对象名)bean表达式外部的对象是由spring容器治理的一个bean对象,表达式外部的名字应该是spring容器中某个bean的name3) within:用于匹配指定包下所有类内的所有办法within(包名+类名)--不罕用5) execution:用于按指定语法规定匹配到具体方法execution(返回值类型 包名.类名.办法名(参数列表))--不罕用7) @annotation:用于匹配指定注解润饰的办法@annotation(注解全类名) 匹配有此注解形容的办法咱们须要本人定义注解,当应用这个注解润饰的类就是指标对象 bean/within表达式个别利用于类级别,实现粗粒度的切入点定义--罕用beanexecution/@annotation表达式利用于办法级别,实现细粒度的切入点表达式定义--罕用@annotation 切面优先级设置当多个切面作用于同一个指标对象办法时,这些切面会构建成一个切面链,切面的优先级须要借助@Order注解进行形容,数字越小优先级越高,默认优先级比拟低.

August 19, 2020 · 1 min · jiezi

关于aop:你不是说你会Aop吗

一大早,小王就急匆匆的跑过来找我,说:周哥,那个记录日志的性能我想求教一下。 因为公司某个我的项目要跟别的平台做对接,咱们这边须要给他们提供一套接口。昨天,我就将记录接口日志的工作安顿给了小王。 上面是我跟小王的次要对话。 我:说说怎么了? 小王:我将记录接口日志的性能放到了每个controller中,当初感觉有点繁琐,我这样做是不是不太适合? 我:为什么要去每个接口里记录日志? 小王:最开始我是用的拦截器,然而这样一个申请就记录了两条记录。 我:为什么是两条? 小王:在preHandle中记录一条申请数据,在postHandle中记录一条响应数据。 我:。。。你不是说你会Aop吗? 小王:Aop也是一样,在前置告诉记录一条申请数据,后置告诉记录一条响应数据。 小王:这个数据和以前记录操作日志的不太一样,以前只须要在前置告诉记录一条操作日志就能够了,然而当初有响应,所以只能在controller中记录日志了。 我:那你知不知道有个盘绕告诉?你说一下Aop就几种告诉类型。 小王:总共有五种,别离是: 前置告诉:在咱们执行指标办法之前运行(@Before)后置告诉:在咱们指标办法运行完结之后,不论有没有异样(@After)返回告诉:在咱们的指标办法失常返回值后运行(@AfterReturning)异样告诉:在咱们的指标办法出现异常后运行(@AfterThrowing)盘绕告诉:指标办法的调用由盘绕告诉决定,即你能够决定是否调用指标办法,joinPoint.procced()就是执行指标办法的代码 。盘绕告诉能够管制返回对象(@Around)接下来,咱们一起来演示一下如何应用盘绕告诉来解决小王的问题。 第一步:提供接口用来接管参数和响应接口 @RestControllerpublic class TestController { @GetMapping("/getName") public String getName(HttpServletRequest request) throw Exception { String result = "Java旅途"; String age = request.getParameter("age"); if("18".equals(age)){ result = "无奈辨认"; } return result; }}第二步:定义切点 execution()是比拟罕用的定义切点的表达式,execution()语法如下: execution(修饰符 返回值 包.类.办法名(参数) throws异样)其中: 修饰符和throws异样能够省略不写 依据这些解释,咱们能够将第一步中的接口用execution()表达式来形容一下: execution(String binzh.website.controller.TestController.GetName(HttpServletRequest))*:匹配所有项..:匹配任意个办法参数..呈现在类名中时,前面必须跟*,示意包、子孙包下的所有类;当初咱们优化一下下面的表达式,定义切面为controller包及controller上面所有包的所有办法 execution(* binzh.website.controller..*.*(..))第三步:盘绕告诉记录日志 @Around("execution(* binzh.website.controller..*.*(..))")public Object around(ProceedingJoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String age = request.getParameter("age"); Object proceed = ""; try { proceed = joinPoint.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("age==="+age); System.out.println("proceed ===="+proceed); return proceed;}运行后果如下: ...

August 4, 2020 · 1 min · jiezi

springaop原理

spring实现aop的基础:BeanPostProcessor原理:https://blog.csdn.net/qizhizh... 2.AOP之@EnableAspectJAutoProxy原理分析https://blog.csdn.net/qizhizh... 3.AnnotationConfigApplicationContext实现spring注解开发https://blog.csdn.net/chr1sgo... 参考:spring中bean的生命周期,spring-@Import注解,

June 17, 2020 · 1 min · jiezi