基于spring注解AOP的异常处理
基于SpringBoot、AOP与自定义注解转义字典值
基于SpringBoot、AOP与⾃定义注解转义字典值 ⼀直以来,前端展⽰字典⼀般以中⽂展⽰为主,若在表中存字典值中⽂,当字典表更改字典值对应的中⽂,会造成数据不⼀致,为此设置冗余字段并⾮最优⽅案,若由前端⾃⼰写死转义,不够灵活,若在业务代码转义,臃肿也不够通⽤,从⽹络上了解到注解、AOP是⼀种不错的解决⽅案,主要有两种⽅式: 1、通过注解获取结果集转为JSON字符串,通过正则查找附加字段; 2、通过获取结果集中相关字段上注解,此种⽅法有两个需要解决的问题,⽗类继承字段、嵌合对象难以解决获取对应注解字段问题,解决起来均⽐较⿇烦; 因此本⽂采⽤第⼀种⽅法,能有效规避第⼆种⽅法相关问题,做到逻辑相对简单,引⼊缓存提⾼效率。
⼀、新建注解 标注⽅法上使⽤1 @Retention(RetentionPolicy.RUNTIME)2 @Target(ElementType.METHOD)3 @Documented4public @interface TranslationDict {5 FieldParam[] value();6 } 注解参数:FieldParam1 @Retention(RetentionPolicy.RUNTIME)2 @Target({ElementType.FIELD})3 @Documented4public @interface FieldParam {56/**7 * 字段类型默认字典8 * Constant.FIELDTYPE_DICT 为⾃定义常量9 * @return10*/11int type() default Constant.FIELDTYPE_DICT;1213/**14 * 字典dictType15 * @return16*/17 String dictType() default "";1819/**20 * 要翻译的字段⽬标字段为翻译的字段+Str21 * @return22*/23 String targetField() default "";2425/**26 * 要翻译的字段值类型27 * @return28*/29 Class targetFieldValueClazz() default String.class;3031 }⼆、注解的使⽤ 在需要转义⽅法体上添加注解,在注解上指定需要转义的字段,不声明则使⽤默认值。
aop注解失效原理与解决
aop注解失效原理与解决
AOP(面向切面编程)注解失效可能涉及多个方面,我将从多个
角度来回答这个问题。
1. 依赖版本冲突,AOP框架通常需要依赖其他框架或库,如果
使用的版本与其他依赖的版本发生冲突,可能会导致AOP注解失效。
解决方法是检查依赖的版本,并确保它们与AOP框架兼容。
2. 执行顺序问题,AOP注解的失效可能与执行顺序有关。
如果
其他切面或者拦截器的执行顺序影响了AOP注解的生效,可能会导
致注解失效。
解决方法是检查AOP的执行顺序,并确保它与预期一致。
3. 注解扫描配置问题,AOP注解失效还可能与注解的扫描配置
有关。
如果AOP框架无法正确扫描到注解,就会导致注解失效。
解
决方法是检查AOP框架的配置,确保注解能够被正确扫描到。
4. 代理对象问题,AOP通常是通过代理对象实现的,如果代理
对象的创建或者使用出现问题,可能导致AOP注解失效。
解决方法
是检查代理对象的创建和使用过程,确保没有问题。
5. 注解使用错误,有时候AOP注解失效是因为注解的使用出现了错误,比如注解放错位置或者参数配置错误等。
解决方法是仔细检查注解的使用,确保符合AOP框架的要求。
总的来说,解决AOP注解失效问题需要综合考虑依赖版本、执行顺序、注解扫描配置、代理对象以及注解使用等多个方面,通过仔细排查可能的原因并逐一解决,才能最终解决AOP注解失效的问题。
OCAP 异常处置行动措施
だ猂
HOLD 硄 め
1
Page 10
5.實際範例介紹
OCAP-004 Rev. 1.2
BGA 模溫超出管制時之處理措施
超出 SPC 管制
讀值超出規格
否
是
將超出管制之點至前 一正常點間所生產的 產品及機器HOLD並召 跚 MRB 會議決定此不 合格產品的處理方式
是
否
否
否
是否位於
讀值位於預
連續7點在中
目錄
前言 1.OCAP 是什麼? 2.OCAP 的結構. 3.OCAP 的範例. 4.如何製作 OCAP? 5.實際範例介紹. 6.實際範例演練.
前言
OCAP (Out of Control Action Plan)
異常處置行動措施是一種工具;累積我 們日常異常處理行動,將其相關的製程異 常發生時的常態處理經驗轉換成流程式 的查檢文件規範行為,讓現場作業人員或 技術人員能自行解決製程上常見問題,而 無須重複執行實驗或浪費太多的人力、 資源、成本、處理時間……等;此方法對 於生產作業、製程改善、異常處理絕對 有其正面的效益貢獻.
“改善對策”活動
“確認有效性”活動
Page 6
4.如何製作 OCAP?
1. 將製程的各步驟畫出來
2. 使用魚骨圖將製程中各步驟有可能
產生管制圖異常的警訊人,機,物,料,法
畫出來
EQUIPMENT
MEASUREMENTS
管制圖超出 管制界線警訊
METHODS
OPERATORS
MATERIALS
Page 7
是否位於 管制界限
是
否
讀值位於預 先管制界限
否
連續7點在中 心線上(下)方
基于SpringBootAOP与自定义注解转义字典值
基于SpringBootAOP与自定义注解转义字典值要基于SpringBoot、AOP和自定义注解来转义字典值,可以按照以下步骤进行:1.创建一个字典表,存储字典值和对应的转义值。
例如,可以创建一个数据库表或者在配置文件中定义一个字典映射关系。
4.在切面方法中,获取需要转义的字段的值,然后根据字典表中的映射关系,找到对应的转义值,并将转义值设置回字段。
5.在需要使用转义值的地方,直接使用被转义后的字段值即可。
下面是一个简单的示例代码:1.创建字典表,例如在配置文件中定义:```yamldict.mapping:gender:0:男1:女``````javaString value( default "";```3.创建AOP切面类:```javapublic class DictTransAspectprivate DictMapping dictMapping;public Object dictTrans(ProceedingJoinPoint joinPoint) throws ThrowableObject result = joinPoint.proceed(;//获取被标记的字段或方法Field field =ReflectionUtils.findField(joinPoint.getTarget(.getClass(, ((MethodSignature) joinPoint.getSignature().getName();DictTrans dictTrans = field.getAnnotation(DictTrans.class);if (dictTrans != null)//获取字段值Object value = field.get(joinPoint.getTarget();//获取字段的字典映射关系Map<String, String> mapping =dictMapping.getMapping(dictTrans.value();//根据字典映射关系转义字段值String transValue = mapping.get(value.toString();//设置转义值回字段field.set(joinPoint.getTarget(, transValue);}return result;}``````javapublic class Userprivate Integer gender;// getter and setter```5.在业务中使用转义后的字段值:```javapublic class UserService// 注入 UserMapper 或者其他数据访问层public User getUserById(String id)User user = userMapper.findById(id);System.out.println(user.getGender(); // 输出转义后的值,例如输出 "男"return user;}```这样,就实现了基于 SpringBoot、AOP 和自定义注解来转义字典值的功能。
aop的原理应用
AOP的原理应用1. 什么是AOPAOP(Aspect-Oriented Programming)是面向切面编程的缩写,它是一种能够通过解耦的方式将横切性关注点模块化的编程范式。
传统的面向对象编程(OOP)主要是通过类和对象来划分和组织代码,但当系统变得复杂时,代码中常常散布着一些与主要业务逻辑无关的、可复用的逻辑(比如日志记录、安全控制、事务管理等),这就导致了代码的重复和耦合度的增加。
而AOP可以通过将这些横切逻辑(称为切面)与主要业务逻辑分离,从而提高代码的可维护性、可测试性和可复用性。
2. AOP的原理AOP的核心原理是在编译期、加载期或运行期利用动态代理技术来实现切面的织入。
具体来说,AOP框架会在目标对象的方法调用前后或者异常抛出时,插入横切逻辑(切面),从而实现对目标对象的增强。
其中,横切逻辑通过切面由切点和增强组成。
•切点:定义了在何处插入切面的准则,比如可以根据类名、方法名或注解等进行精确定位。
•增强:指的是横切逻辑的实现,比如可以在方法调用前后执行某些操作。
织入过程可以通过前置织入、后置织入等方式来实现。
3. AOP的应用场景AOP的特点使得它在很多场景下都能够发挥作用,以下列举了几个常见的应用场景:•日志记录:AOP可以很方便地将日志记录逻辑与主要业务逻辑分离,从而使得代码更加清晰、易于维护。
例如,可以利用AOP在方法调用前后记录方法的输入参数和返回结果。
•安全控制:通过AOP可以在方法调用前进行身份验证、权限检查等安全控制逻辑,从而确保系统的安全性。
•事务管理:AOP可以在方法调用前后添加事务管理逻辑,保证数据的一致性和完整性。
例如,可以在方法调用前开启事务,在方法调用后提交或回滚事务。
•性能监控:利用AOP可以在方法调用前后统计方法的执行时间、请求次数等,通过监控这些性能指标可以优化系统的性能。
•异常处理:AOP可以在方法抛出异常时进行异常处理逻辑,并且可以根据异常类型进行不同的处理。
基于Annotation的Spring AOP日志处理的设计与实现
Value Engineering0引言AOP (Aspect Oriented Programming ,向切面编程)是建立在OOP (Object Oriented Programming ,面向对象程序设计)基础之上的,OOP 针对问题领域中以及业务处理过程中存在的实体及其属性和操作进行抽象和封装,面向对象的核心概念是纵向结构的,其目的是获得更加清晰高效的逻辑单元划分;而AOP 则是针对业务处理过程中的切面进行提取,例如,某一个操作(例如日志输出)在各个模块中都有涉及,这个操作就可以看成“横切”存在于系统当中。
在许多情况下,这些操作都是与业务逻辑相关性不强或者不属于逻辑操作的必须部分,而面向对象的方法很难对这种情况做出处理。
AOP 则将这些操作与业务逻辑分离,使程序员在编写程序时可以专注于业务逻辑的处理,而利用AOP 将贯穿于各个模块间的横切关注点自动耦合进来[1]。
AOP 被定义为一种编程技术,用来在系统中提升业务的分离,它将服务模块化,使得业务层完全没必要理会这些服务的存在,比如日志,事务,安全等。
1Spring AOP 的Annotation 方式的技术要点1.1Annotation 技术sun 公司从J2SE 5.0开始提供名为Annotation (注释)的功能,它被定义为JSR-175规范[2],是Java 语言中的一种特殊的元数据语法,可以被添加到Java 代码中。
类,方法,变量,参数,包都可以被标注。
Annotation 是可以被反射的,因为它们被编译器生成嵌入在编译后文件,并保留在虚拟机中以便在运行时被索引[3]。
注释是以“@注释名”在代码中存在,一般只有一行,也可以包含有任意的参数。
从Spring2.0以后的版本中,集成了AspectJ 注解。
AOP 的实现有多种方式,使用Annotation 方式的配置,无需配置文件,只需要通过添加“注释代码”来完成,简化了Spring 的开发,容易对方法进行拦截。
spring事务详解(基于注解和声明的两种实现方式)
spring事务详解(基于注解和声明的两种实现⽅式)Spring事务( Transaction )事务的概念事务是⼀些sql语句的集合,作为⼀个整体执⾏,⼀起成功或者⼀起失败。
使⽤事务的时机⼀个操作需要多天sql语句⼀起完成才能成功程序中事务在哪⾥说明加在业务类的⽅法上⾯(public⽅法上⾯),表⽰业务⽅法执⾏时,需要事务的⽀持。
不同的事务管理器不同的数据库访问技术,处理事务是不同的1. 使⽤jdbc访问数据库,事务处理public void updateAccount(){Connection con = .....;con.setAutoCommit(false);state.insert();state.update();mit();con.setAutoCommit(true);}2. MyBatis执⾏数据库,处理事务public void updateAccount(){SqlSession sqlSession = SqlSessionFactory.openSession(false);try{sqlSession.insert(...);sqlSession.update(...);mit();}catch(Exception e){sqlSession.rollback();}}spring统⼀管理事务,把不同的数据库访问技术的事务处理统⼀起来使⽤spring的事务管理器,管理不同数据库访问技术的事务处理。
开发⼈员只需要掌握spring的事务处理⼀个⽅案,就可以实现使⽤不同数据库访问技术的事务管理。
尽管事务⾯向的是spring,有spring管理事务,做事务提交和回滚。
spring事务管理器spring框架使⽤事务管理器对象,管理所有的事务。
事务管理器接⼝: PlatFormTransactionManager作⽤:定义了事务的操作,主要是commit() , rollback()事务管理器有很多的实现类:⼀种数据库访问计数有⼀个实现类。
Spring3.0异常处理配置
5. @Controller 6. public class ExceptionHandlerController { 7. 8. 9. 10. 11. 12. 13. 14. } } @ExceptionHandler(value={IOException.class,SQLException.class}) public String exp(Exception ex,HttpServletRequest request) { request.setAttribute("ex", ex); return "/error.jsp";
从目前的调查结果看,这两种方式不能共存,不知道未来的版本是否能将他们合二为一,这 样才能灵活配置。
基于 HandlerExceptionResolver 接口的异常处理:
使用这种方式只需要实现 resolveException 方法,该方法返回一个 ModelAndView 对象, 在方法内部对异常的类型进行判断,然后常见合适的 ModelAndView 对象,如果该方法返 回了 null,则 Spring 会继续寻找其他的实现了 HandlerExceptionResolver 接口的 Bean。 换句话说,Spring 会搜索所有注册在其环境中的实现了 HandlerExceptionResolver 接口的 Bean,逐个执行,直到返回了一个 ModelAndView 对象。 示例代码:
SimpleMappingExceptionResolver 类, 该类实现了 HandlerExceptionResolver 接口, 需 要使用时只需要使用<bean/>节点进行声明即可,示例如下:
Java框架------Spring框架AOP注解(@Aspect和@Around)
Java框架------Spring框架AOP注解(@Aspect和@Around)AOP 中的声明主要有两种基于XML和基于Annotation之前的为借助xml ,现在介绍⼀下借助注解的⽅式,修改之前的⼩项⽬常见五种通知类型org.springframework.aop.MethodBeforeAdvice(前置通知)在⽅法之前⾃动执⾏的通知称为前置通知,可以应⽤于权限管理等功能。
org.springframework.aop.AfterReturningAdvice(后置通知)在⽅法之后⾃动执⾏的通知称为后置通知,可以应⽤于关闭流、上传⽂件、删除临时⽂件等功能。
org.aopalliance.intercept.MethodInterceptor(环绕通知)在⽅法前后⾃动执⾏的通知称为环绕通知,可以应⽤于⽇志、事务管理等功能。
org.springframework.aop.ThrowsAdvice(异常通知)在⽅法抛出异常时⾃动执⾏的通知称为异常通知,可以应⽤于处理异常记录⽇志等功能。
org.springframework.aop.IntroductionInterceptor(引介通知)在⽬标类中添加⼀些新的⽅法和属性,可以应⽤于修改旧版本程序(增强类)。
常见注解@Aspect:作⽤是把当前类标识为⼀个切⾯供容器读取@Around:环绕增强,相当于MethodInterceptor@AfterReturning:后置增强,相当于AfterReturningAdvice,⽅法正常退出时执⾏@Pointcut:Pointcut是植⼊Advice的触发条件。
每个Pointcut的定义包括2部分,⼀是表达式,⼆是⽅法签名。
⽅法签名必须是 public及void型。
可以将Pointcut中的⽅法看作是⼀个被Advice引⽤的助记符,因为表达式不直观,因此我们可以通过⽅法@Before:标识⼀个前置增强⽅法,相当于BeforeAdvice的功能,相似功能的还有@AfterThrowing:异常抛出增强,相当于ThrowsAdvice@After: final增强,不管是抛出异常或者正常退出都会执⾏使⽤pointcut代码@DeclareParents ⽤于定义引介通知,相当于IntroductionInterceptor(不要求掌握)。
举例说明事务注解失效的场景
举例说明事务注解失效的场景事务注解是在Spring框架中非常常用的一种方式,用于管理数据库事务。
但是在某些场景下,事务注解可能会失效,导致事务无法正常管理。
本文将举例说明事务注解失效的场景。
一、Spring AOP代理问题Spring AOP代理是实现事务注解的重要手段之一。
但是,在某些情况下,AOP代理可能会失效,导致事务无法正常管理。
1.1 代理对象为类而不是接口当我们使用基于类的AOP代理时,如果被代理的对象没有实现任何接口,则Spring将会使用CGLIB创建一个子类来实现AOP。
这个子类并不会继承父类上的@Transactional注解,因此在使用该子类时,事务注解将会失效。
1.2 代理对象不是由Spring容器创建如果我们手动创建了一个对象,并且使用了@Transactional注解来管理它的事务,则该注解将不起作用。
因为Spring只能对由容器创建的Bean进行AOP代理。
二、多线程问题当我们在多线程环境下使用事务注解时,可能会遇到以下问题:2.1 一个线程中开启了一个新的事务,并在该线程中进行了操作;另一个线程中也开启了一个新的事务,并尝试对第一个线程所操作过的数据进行操作。
此时,第二个线程将无法获取到第一个线程所开启的事务,从而导致事务注解失效。
2.2 在多线程环境下,如果我们使用ThreadLocal来管理事务,则可能会遇到线程池重用问题。
当一个线程执行完毕后,我们需要手动清除ThreadLocal中的内容,否则当该线程被再次使用时,它仍然会持有之前的ThreadLocal内容,从而导致事务注解失效。
三、异常处理问题在使用@Transactional注解时,我们需要注意异常处理问题。
如果我们在方法中捕获了异常,并且没有将其向上抛出,则该异常将不会被Spring捕获到,并且事务将不会回滚。
四、数据库引擎问题在某些数据库引擎中,例如MyISAM,在执行DML操作时并不支持事务。
因此,在使用这些数据库引擎时,即使我们使用了@Transactional注解来管理事务,也无法实现回滚操作。
Spring中解决事务以及异步注解失效
Spring中解决事务以及异步注解失效一、重现@Transaction失效的场景有如下业务场景,新增订单后,自动发送短信,下面的代码在同一个类中:@Transactionpublic void addOrder(OrderInfo orderInfo){orderMapper.insert(orderInfo);try{sendMesg(orderInfo );}cach(Exception e){e.printStrace();}}@Transactionpublic void sendMesg( OrderInfo orderInfo ){mesgMapper.insert(orderInfo );throws new RuntimeException("发送短信出现异常!");}上面的伪代码模拟新增订单后,自动发送短信的业务场景。
两个操作被标识为事务,为了不影响发送短信出现异常影响订单的插入,在调用发送短信的方法时,通过 try....cach...捕获其异常并处理,不影响订单表的插入。
因为sendMesg标识为事务,其抛出异常后,事务按正常逻辑来说,事务会进行回滚,即短信表中不会插入记录。
然而事与愿违,出现的结果是短信表也插入了记录。
二、重现异步注解失效的场景1、异步注解@Async介绍基于@Async标注的方法,称之为异步方法,这些方法在执行的时候,spring将会为其开辟独立的线程执行,调用者无需等待它的完成,即可继续其他的操作。
2、如何使用@Async增加 aspectj 相关的依赖;修改 spring配置文件,在配置文件中增加如下配置:<task:annotation-driven executor = "annotationExecutor" /><task:executor id="annotationExecutor" pool-size="20" />在方法上加上@Async注解。
autowired注解nosuchbeandefinitionexception
autowired注解nosuchbeandefinitionexception NoSuchBeanDefinitionException是Spring框架的一个异常,表示在容器中找不到特定名称或类型的bean。
当使用@Autowired注解自动装配bean时,如果容器中找不到与注入类型或名称匹配的bean,就会抛出这个异常。
可能的原因和解决方法包括:
1.Bean没有被正确声明或扫描:确保bean被正确声明并且可以被Spring容器
扫描到。
使用@Component、@Service、@Repository等注解标记类,或者在XML配置文件中声明bean。
2.包扫描设置正确:如果使用了包扫描,确保包含了需要扫描的bean的包路
径。
使用@ComponentScan注解可以设置扫描的基本包路径。
3.检查注入的名称或类型:确保@Autowired注解的目标类型或名称与实际
bean的类型或名称匹配。
可以使用@Qualifier注解指定特定的bean名称进行装配。
4.依赖项不完整:有时候这个异常可能是因为依赖项不完整导致的。
检查依赖
项和配置,确保它们可以正确地注入到需要的地方。
5.确保容器启动成功:确保Spring容器在启动时没有任何异常,否则可能会导
致bean无法正确注册或装配。
通过检查这些方面,可以定位到可能导致NoSuchBeanDefinitionException的问题,并尝试解决它。
SpringBoot拦截全局异常统一处理(RestControllerAdvice注解)
SpringBoot拦截全局异常统一处理(RestControllerAdvice注解)public class GlobalExceptionHandlerpublic ResponseEntity<String> handleException(Exception ex) //处理逻辑returnResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");}public ResponseEntity<String> handleUserNotFoundException(UserNotFoundException ex) //处理逻辑return ResponseEntity.status(HttpStatus.NOT_FOUND).body("用户不存在");}//其他异常处理方法在上面的代码中,我们定义了两个异常处理方法。
第一个方法用来处理所有Exception类型的异常,第二个方法用来处理UserNotFoundException类型的异常。
在异常处理方法中,我们可以根据具体的业务需求对异常进行处理。
我们可以返回合适的HTTP状态码和相应的错误信息,或者进行其他一些逻辑处理。
当应用中抛出对应的异常时,全局异常处理类会拦截这些异常,并调用对应的异常处理方法进行处理。
然后根据处理方法中的返回结果,返回给客户端合适的响应。
除了处理异常方法,全局异常处理类还可以定义其他方法,比如处理参数校验失败、权限不足等情况的方法。
这样,在应用的任何地方抛出这些异常时,都可以统一处理。
spring中aop不生效的几种解决办法
spring中aop不⽣效的⼏种解决办法先看下这个问题的背景:假设有⼀个spring应⽤,开发⼈员希望⾃定义⼀个注解@Log,可以加到指定的⽅法上,实现⾃动记录⽇志(⼊参、出参、响应耗时这些)package blogs.yjmyzz.springbootdemo.aspect;import ng.annotation.ElementType;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;import ng.annotation.Target;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Log {}然后再写⼀个Aspect来解析这个注解,对打了Log注解的⽅法进⾏增强处理 package blogs.yjmyzz.springbootdemo.aspect;import ng.JoinPoint;import ng.ProceedingJoinPoint;import ng.annotation.Around;import ng.annotation.Aspect;import ng.annotation.Pointcut;import ponent;import ng.reflect.Method;@Component@Aspectpublic class LogAspect {@Pointcut("execution (* blogs.yjmyzz.springbootdemo.service..*.*(..))")public void logPointcut() {}@Around("logPointcut()")public void around(JoinPoint point) {String methodName = point.getSignature().getName();Object[] args = point.getArgs();Class<?>[] argTypes = new Class[point.getArgs().length];for (int i = 0; i < args.length; i++) {argTypes[i] = args[i].getClass();}Method method = null;try {method = point.getTarget().getClass().getMethod(methodName, argTypes);} catch (Exception e) {e.printStackTrace();}//获取⽅法上的注解Log log = method.getAnnotation(Log.class);if (log != null) {//演⽰⽅法执⾏前,记录⼀⾏⽇志System.out.println("before:" + methodName);}try {//执⾏⽅法((ProceedingJoinPoint) point).proceed();} catch (Throwable throwable) {throwable.printStackTrace();} finally {if (log != null) {//演⽰⽅法执⾏后,记录⼀⾏⽇志System.out.println("after:" + methodName);}}}}写⼀个测试Service类:package blogs.yjmyzz.springbootdemo.service;import blogs.yjmyzz.springbootdemo.aspect.Log;import ponent;@Componentpublic class HelloService {@Logpublic void sayHi(String msg) {System.out.println("\tsayHi:" + msg);}public void anotherSayHi(String msg) {this.sayHi(msg);}}最后来跑⼀把:package blogs.yjmyzz.springbootdemo;import blogs.yjmyzz.springbootdemo.service.HelloService;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import ponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;/*** @author 菩提树下的杨过*/@ComponentScan("blogs.yjmyzz")@Configuration@EnableAspectJAutoProxypublic class SampleApplication {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SampleApplication.class);HelloService helloService = context.getBean(HelloService.class);helloService.sayHi("hi-1");System.out.println("\n");helloService.anotherSayHi("hi-2");}}输出如下:显然HelloService中的anotherSayHi⽅法,并未被aop增强。
详解SpringAOP自定义可重复注解没有生效问题
详解SpringAOP⾃定义可重复注解没有⽣效问题⽬录1. 问题背景2. 不啰嗦,上代码3. 问题排查3.1 是不是切点写得有问题,于是换成如下形式:3.2 是不是使⽤的地⽅不是代理对象4. 问题原因1. 问题背景⼯作中遇到这样的场景:某个⽅法需要在不同的业务场景下执⾏特定的逻辑,该⽅法已经上⽣产,不想改变原来的代码,因此决定⽤AOP做个切⾯执⾏逻辑。
2. 不啰嗦,上代码以下为核⼼代码:定义注解:@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documented@Repeatable(value = StartTaskRuns.class)public @interface StartTaskRun {int businessType() default 0;}@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface StartTaskRuns {StartTaskRun[] value();}定义切⾯@Aspect@Componentpublic class StartTaskRunAspect {@AfterReturning(pointcut = "@annotation(com.freedom.code.annotation.StartTaskRun)", returning = "retValue")public void startTask(JoinPoint joinPoint, Object retValue) throws Exception {Object[] args = joinPoint.getArgs();Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();StartTaskRun[] annotations = method.getAnnotationsByType(StartTaskRun.class);for (StartTaskRun annotation : annotations) {System.out.println(annotation.businessType());}}}业务代码加注解@StartTaskRun(businessType = 5)@StartTaskRun(businessType = 6)@Override@Transactional(rollbackFor = Exception.class)public String doCsmsStrategy(Long id) {// 业务逻辑return userDO.getId().toString();}debug的时候发现,切⾯的代码没有执⾏。
autowired注解跨模块报空指针
@Autowired是Spring 框架中的一个注解,用于自动装配bean。
如果你在使用@Autowired时遇到了空指针异常(NullPointerException),这通常意味着Spring 容器在尝试注入bean 时无法找到匹配的bean。
如果你在跨模块时遇到这个问题,以下是可能的原因和解决方案:1.模块间的依赖问题:确保你的模块之间有正确的依赖关系。
如果你正在尝试自动装配的bean 存在于另一个模块中,那么那个模块必须被正确地包含在当前模块的依赖中。
2.Spring Boot 的自动配置:如果你使用的是Spring Boot,确保你的所有模块都启用了Spring Boot 的自动配置。
3.组件扫描:确保Spring 知道在哪里查找带有@Component、@Service、@Repository或@Controller注解的类。
你可以使用@ComponentScan来指定扫描的包。
4.组件的可见性:如果一个bean 是私有的,Spring 容器无法访问它,因此不能进行自动装配。
确保你想要自动装配的bean 是public的。
5.检查注解的位置:确保@Autowired注解用于类的字段、构造函数或方法上。
6.版本冲突:有时,不同模块之间的版本冲突可能会导致一些奇怪的错误。
确保你的所有依赖项都是兼容的版本。
7.自定义命名:如果你为bean 指定了自定义名称,确保你在@Autowired中使用了正确的名称。
8.使用@Qualifier注解:当有多个相同类型的bean 时,你可以使用@Qualifier注解来指定要注入哪个bean。
9.查看详细的错误堆栈:查看完整的错误堆栈跟踪,这可能会为你提供更多关于问题的线索。
10.其他配置问题:检查其他与Spring 和依赖注入相关的配置,确保没有遗漏或错误的配置。
如果上述建议都不能解决你的问题,建议提供更详细的错误信息和代码示例,以便更准确地诊断问题所在。
SpringAOP注解为什么失效?90%Java程序员不知道
SpringAOP注解为什么失效?90%Java程序员不知道使用Spring Aop注解的时候,如@Transactional, @Cacheable 等注解一般需要在类方法第一个入口的地方加,不然不会生效。
如下面几种场景1、Controller直接调用Service B方法:Controller > ServiceA在Service A 上加@Transactional的时候可以正常实现AOP功能。
2、Controller调用Service A方法,A再调用B方法:Controller > Service A > Service B在Service B上加@Transactional的时候不能实现AOP功能,因为在Service A方法中调用Service B方法想当于使用this.B(),this 代表的是Service类本身,并不是真实的代理Service对象,所以这种不能实现代理功能。
所以,如果不是直接调用的方式,是不能实现代理功能的,非常需要注意。
但确实有这种不是直接调用的试,也需要实现代理功能,怎么做呢?很简单,只需要暴露当前代理对象给当前线程就行了,如下配置,注解粗体的部分。
<!-- aspect --><aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>protected final T proxy() {return (T) AopContext.currentProxy();}这样就能拿到代理对象了,在Service A中可以通过proxy().B()即可正常实现B方法上面的代理功能。
看下AopContext源码,Spring会将当前代理对象绑定到当前线程ThreadLocal上面。
关于线程绑定变量参考昨天分享的ThreadLocal文章。
spring使用aspect注解切面不起作用的排查过程及解决
spring使⽤aspect注解切⾯不起作⽤的排查过程及解决今天做spring使⽤aspect注解demo,发现不起作⽤,问题排查如下:1.程序正常启动,说明jar包依赖没有问题2.debug程序不进⼊切⾯,有可能是路径问题,根据这个思路,果真是路径问题,在切⾯配置类的使⽤@ComponentScan的路径写错了。
扫描的路径为:注解类、切⾯类及service的上⼀层⽬录即可,假设项⽬的结构如下:则@ComponenScan(".nrt")即可SpringBoot切⾯@aspect--- 注解在嵌套⽅法不⽣效的问题例如在service中⽅法如下@PermissionAop@Overridepublic List<PoiPermission> getList() {List<PoiPermission> list = this.list();return list;}@Overridepublic void test(){this.getList();System.out.println("");}controller中调⽤test()⽅法,test⽅法中调⽤切⾯⽅法,切⾯不⽣效,⽆法进⼊切⾯。
使⽤如下⽅式可解决该问题(启动类上需要添加@EnableAspectJAutoProxy(exposeProxy = true))@PermissionAop@Overridepublic List<PoiPermission> getList() {List<PoiPermission> list = this.list();return list;}@Overridepublic void test(){IPoiPermissionService service = (IPoiPermissionService) AopContext.currentProxy();service.getList();System.out.println("");}其中IPoiPermissionService为该service类实现的接⼝。
记一次SpringBootAspect不生效解决过程
记⼀次SpringBootAspect不⽣效解决过程转⾃我的个⼈博客:问题描述项⽬中两个aspect,⼀个环绕controller,⽤于记录⽇志,能够正常在point处进⼊aspect处理;另⼀个aspect 的point设于service,死活不能进⼊。
解决思路1、⾸先排查pointcut配置是否正确,检查后发现没有问题;2、我们都知道spring的aop运⽤的是动态代理技术,由spring托管的bean⼤多为代理bean,controller层打印service对象,发现service对象竟然直接是service实现类的“本尊”。
如下图所⽰:再看springboot启动⽇志,发现roleServiceImpl实例化的时候有如下提⽰:Bean 'roleServiceImpl' of type [com.gaoxiaobo.wms.service.impl.RoleServiceImpl] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)那么问题就明了了,我们在controller层调⽤的roleServiceImpl对象⾮代理对象⽽是其本⾝,那么对其的aspect是不会⽣效的,不仅aspsect不会⽣效,事务注解@Transactional也不会⽣效,问题还是相当严重的。
那么,why 没有⽣成其代理对象呢?⼀定是哪⾥先调⽤了roleServiceImpl导致spring优先实例化了该bean;通过排查,找到了罪魁祸⾸:shiro 的LifecycleBeanPostProcessor优先实例化⾃定义Realm,⾃定义的Realm依赖于roleService,导致roleService被初始化。
解决⽅法⾃定义realm中roleService设置成懒加载。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/** * 将内容输出到浏览器 * * @param content 输出内容 */ private void writeContent(String content) {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); response.reset(); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Type", "text/plain;charset=UTF-8"); response.setHeader("icop-content-type", "exception"); PrintWriter writer = null; try {
<context:component-scan base-package="com.sishuok.es" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
/** * 拦截 web 层异常,记录异常日志,并返回友好信息到前端 * 目前只拦截 Exception,是否要拦截 Error 需再做考虑 * * @param e 异常对象 */ @AfterThrowing(pointcut = "webPointcut()", throwing = "e") public void handleThrowing(Exception e) {
v 二、基于@ControllerAdvice(加强的控制器)的异常处理 参考文档:/blog/1866350
@ControllerAdvice 注解内部使用@ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法应用到所有的 @RequestMapping 注解的方法。本例子中使用 ExceptionHandler 应用到所有 @RequestMapping 注解的方法,处理发生的异常。
public class WebExceptionAspect { private static final Logger LOGGER = LoggerFactory.getLogger(WebExceptionAspect.class);
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") private void webPointcut() {}
示例代码:
复制代码 import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody;
import com.hjz.exception.ServiceException; import com.hjz.exception.utils.ExceptionUtils;
import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter;
import com.hjz.exception.ServiceException; import com.hjz.exception.utils.ExceptionUtils;
@ResponseBody public class ExceptionAdvice {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionAdvice.class);
writer = response.getWriter(); } catch (IOException e) {
e.printStackTrace(); } writer.print(content); writer.flush(); writer.close(); } }
复制代码 2.处理 service 层的异常 ServiceExceptionAspect .java
/** * @within(org.springframework.stereotype.Service),拦截带有 @Service 注解的类的所有方法 * @annotation(org.springframework.web.bind.annotation.RequestMapping),拦截带有@RquestMapping 的注解方法 */ @Pointcut("@within(org.springframework.stereotype.Service) && execution(public * *(..))") private void servicePointcut() {}
复制代码 import ng.JoinPoint; import ng.annotation.AfterThrowing; import ng.annotation.Aspect; import ng.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ponent; import org.springframework.util.StringUtils;
</context:component-scan>
v 三、基于 AOP 的异常处理 1.处理 controller 层的异常 WebExceptionAspect.java
复制代码 import ng.annotation.AfterThrowing; import ng.annotation.Aspect; import ng.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ponent; import org.springframework.util.StringUtils; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;
/** * web 异常切面 * 默认 spring aop 不会拦截 controller 层,使用该类需要在 spring 公共配置文件中注入改 bean, * 另外需要配置<aop:aspectj-autoproxy proxy-target-class="true"/> */ @Aspect
//不需要再记录 ServiceException,因为在 service 异常切面中已经记录过 if (!(e instanceof ServiceException)) {
LOGGER.error(ExceptionUtils.getExcTrace(e));
}
HttpHeaders headers = new HttpHeaders(); headers.set("Content-type", "text/plain;charset=UTF-8"); headers.add("icop-content-type", "exception"); String message = StringUtils.isEmpty(e.getMessage()) ? "系统异常!!" : e.getMessage(); return new ResponseEntity<>(message, headers, HttpStatus.OK); } } 复制代码 如果不起作用,请检查 spring-mvc 的配置文件,是否有 ControllerAdvice 的如下配置