Spring Aop 采用注解方式开发
- 格式:doc
- 大小:74.00 KB
- 文档页数:4
在Spring AOP中,ProceedingJoinPoint是一个接口,它用于表示连接点(在AOP术语中,连接点是应用程序执行的点,如方法调用)以及它们的执行。
ProceedingJoinPoint接口提供了一种获取方法参数的注解的方式,让你可以在通知中访问和操作这些参数。
下面是如何使用ProceedingJoinPoint来获取方法参数的注解的详细解释:首先,假设你有一个Spring管理的bean,其中包含一个带有注解的方法:@Servicepublic class MyService {public void myMethod(@MyAnnotation String param){// 方法实现}}在上述代码中,myMethod方法有一个名为param的参数,它被@MyAnnotation注解标记。
接下来,你可以创建一个切面,并在切面中使用ProceedingJoinPoint来获取方法参数的注解:@Aspect@Componentpublic class MyAspect {@Around("execution(* com.example.MyService.myMethod(..))")public Object myAdvice(ProceedingJoinPoint joinPoint)throws Throwa ble{// 获取目标方法的参数Object[] methodArgs = joinPoint.getArgs();// 获取参数上的注解for(Object arg : methodArgs){if(arg !=null){MyAnnotation annotation = arg.getClass().getAnnotation (MyAnnotation.class);if(annotation !=null){// 找到具有 @MyAnnotation 注解的参数// 可以在此处执行相应的逻辑}}}// 继续执行原始方法return joinPoint.proceed();}}在上述代码中,我们创建了一个名为myAdvice的通知,使用@Around注解,它围绕目标方法执行。
基于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 和自定义注解来转义字典值的功能。
记录SpringBoot2.3.4.RELEASE版注解⽅式实现AOP和通知的执⾏顺序1.advice 按照以下的顺序执⾏输出结果:(正常和异常)说明:Spring boot 2.3.4.RELEASE 版本使⽤的AOP是spring-aop-5.2.9.RELEASE,AOP的通知顺序不⼀样。
可以测试下Spring boot 2.1.1.RELEASE 版做对⽐,发现结果是不⼀样的。
2.代码实现public class User {private String userName;private String password;public String getUserName() {return userName;}public void setUserName(String userName) {erName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User [userName=" + userName + ", password=" + password + "]";}}实体类:Userpublic interface UserService {public void printUser(User user);}Service接⼝@Servicepublic class UserServiceImpl implements UserService {@Overridepublic void printUser(User user) {System.out.println(user.toString());}}Service实现类//定义切⾯@Aspectpublic class MyAspect {//定义切点@Pointcut("execution(* erServiceImpl.printUser(..))")public void pointCut() {}@Before("pointCut()")public void before() {System.out.println("-----Before-----");}@After("pointCut()")public void after() {System.out.println("-----After-----");}@AfterReturning("pointCut()")public void afterReturning() {System.out.println("-----AfterReturning-----");//System.out.println("事务提交");}@AfterThrowing("pointCut()")public void afterThrowing() {System.out.println("-----AfterThrowing-----");//System.out.println("事务回滚");}@Around("pointCut()")public void around(ProceedingJoinPoint pjp) throws Throwable{System.out.println("around advise 1");pjp.proceed();//回调⽬标对象的原有⽅法System.out.println("around advise2");}}切⾯@SpringBootApplicationpublic class AopApplication {@Bean("myAspect")public MyAspect getMyAspect() {return new MyAspect();}public static void main(String[] args) {SpringApplication.run(AopApplication.class, args);}}Spring Boot启动类<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 https:///xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version><!-- <version>2.1.1.RELEASE</version> --><relativePath /> <!-- lookup parent from repository --></parent><groupId>com.springbootTest.aop</groupId><artifactId>aop</artifactId><version>0.0.1-SNAPSHOT</version><name>aop测试</name><description>Demo project for Spring Boot</description> <properties><java.version>1.8</java.version></properties><dependencies><!-- SpringBoot 核⼼包 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- SpringBoot Web容器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- SpringBoot 拦截器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></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></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin></plugins></build></project>pom.xml。
spring纯注解⽅式与AOPspring注解⽅式以前我也使⽤过纯注解⽅式.现在在这⾥做个记录 我们先认识⼏个我们都⽿熟能详的注解 @configuration :从spring3.0这个注解就可以⽤于定义配置类,可以替换xml配置⽂件,相当于beans的根标签,配置类中可以包含⼀个或者多个@bean注解这些⽅法都会被⼀个AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进⾏扫描,并⽤于构建bean定义,初始化Spring容器。
@bean: 相当于 bean@componentScan@PropertySource 相当于context:property-placeholder标签如果是在类路径下,需要加上classpath 和@value 配合使⽤/*** 相当于⼀个beans*/@Configuration@ComponentScan(basePackages = "xiaodao.spring")public class SpringConfiguration {public SpringConfiguration() {System.out.println("spring 容器启动");}/*** bean id 默认是bean的⽅法名* @return*//* @Beanpublic UserService userService(){return new UserServiceImpl();}*/}public class SpringConfigurationTest {@Testpublic void test1(){//创建纯注解⽅式的spring 容器ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);UserService userService = (UserService) applicationContext.getBean("userService");userService.save();}}spring 分模块开发@import 注解的使⽤⽅法 我们在spring中有各种各样的配置⽂件.写在⼀个类中,肯定是不合适的.我们需要分门分类@Configuration@ComponentScan(basePackages = "com.kkb.spring")@Import({ JdbcConfig.class})public class SpringConfiguration {}@Configuration@PropertySource("classpath:jdbc.properties")public class JdbcConfig{}什么是AOP呢? AOP为Aspect Oriented Programming的缩写,意为:⾯向切⾯编程 AOP最早是AOP联盟的组织提出的,指定的⼀套规范,spring将AOP的思想引⼊框架之中,通过预编译⽅式和运⾏期间动态代理实现程序的统⼀维护的⼀种技术, 预编译⽅式在spring中没有使⽤,因为要结合其他编译⽅式,和spring造成强耦合,预编译⽅式就是在程序没有运⾏前编译. AOP是OOP的延续,,AOP解决的是从横向解决代码重复的问题 ,OOP是从纵向解决代码的重复问题 AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)讲业务逻辑和系统处理的代码进⾏解耦如如:关闭连接事物管理,操作⽇志的记录AOP 的相关术语?1. Joinpoint(连接点) -- 所谓连接点是指那些被拦截到的点。
java spring 入门教程Java Spring是一个开源的轻量级Java开发框架,是当今Java企业级应用开发的首选框架之一。
它提供了一个全面的编程和配置模型,可以帮助开发者更加高效地构建可靠的、灵活的、可扩展的企业级应用。
首先,Java Spring框架的核心概念是控制反转(IoC)和面向切面编程(AOP)。
控制反转是指将对象的创建、组装和管理等工作交给Spring容器来完成,而不是由开发者手动创建和管理。
这样做的好处是降低了开发复杂度,提高了代码的可测试性和可维护性。
面向切面编程是指通过横切关注点将应用程序业务逻辑与系统级服务(如日志记录、事务管理等)进行解耦,从而提高代码的可重用性和可维护性。
其次,Java Spring框架提供了一系列的容器和模块,用于支持不同层次的应用开发。
其中,核心容器包括BeanFactory和ApplicationContext,用于管理和控制对象的生命周期。
数据访问模块提供了对数据库访问的支持,包括对JDBC、ORM框架如Hibernate、MyBatis和Spring Data等的集成。
还有Web开发模块,提供了对Servlet、WebSocket、RESTful服务等的支持。
此外,还有安全性、消息队列、缓存等模块可以根据需要进行集成和使用。
此外,Java Spring还采用了一种基于注解的开发模式,使得开发者可以通过简单的注解配置和元数据来实现各种功能。
比如,使用@Component注解可以将一个Java类标记为一个可被Spring容器管理的Bean;使用@Autowired注解可以自动装配Bean之间的依赖关系;使用@Controller和@RequestMapping注解可以实现Web请求的处理等。
这种开发方式提高了开发效率,同时使得代码更加清晰和易于维护。
最后,Java Spring框架还提供了一系列的特性和工具,用于提高应用的性能和可用性。
比如,Spring Boot是一个快速构建应用程序的工具,通过自动配置和约定大于配置的原则,极大地简化了项目的搭建和部署。
aop处理传入参数
AOP(面向切面编程)是一种编程范式,旨在通过将系统的功能模块化,使得程序的各个部分能够独立开发、测试和维护,同时提高代码的可重用性和可扩展性。
在AOP中,处理传入参数是实现模块之间交互的重要方式之一。
在AOP中,处理传入参数的方式主要有以下几种:
1.注解方式:通过在方法上添加特定的注解,AOP框架可以自动识别并处理
传入参数。
例如,在使用Spring AOP框架时,可以使用@Around注解定义一个环绕通知,该通知可以访问方法的传入参数。
2.拦截器方式:AOP框架通常提供了拦截器(Interceptor)机制,可以在方
法执行前后插入自定义逻辑。
通过实现拦截器,可以对传入参数进行预处理或后处理。
例如,在Spring AOP中,可以使用Ordered拦截器对传入参数进行排序。
以上信息仅供参考,如有需要,建议咨询专业编程人员。
aop切面类注解AOP(Aspect Oriented Programming)是一种编程范式,用于解决传统面向对象编程中的一些难题,比如横切关注点(cross-cutting concerns)的复用和统一管理。
AOP的核心思想是将程序的功能划分为核心业务逻辑和横切关注点两部分,通过对横切关注点的抽象和封装,实现对核心业务逻辑的解耦和复用。
在Spring框架中,AOP是一个重要的组成部分,通过切面(Aspect)和通知(Advice)两个核心概念,实现面向切面编程(Aspect Oriented Programming)。
切面定义了横切关注点的逻辑,通知定义了在何时、何地执行切面的逻辑。
通过在Spring容器中声明切面和通知的关系,可以实现在程序运行过程中动态地将横切关注点织入到核心业务逻辑中。
除了使用XML配置文件外,Spring还提供了基于注解的AOP支持,其中最常用的是@Aspect注解。
通过在切面类上添加@Aspect注解,再结合@Pointcut、@Before、@After、@Around等注解,可以实现对横切关注点的定义和精确控制。
相比XML配置文件,基于注解的AOP配置更加简洁和直观,易于理解和维护。
使用AOP切面类注解的方式,可以有效提高代码的可维护性和扩展性。
通过将横切关注点的逻辑抽象为切面类,实现对核心业务逻辑的解耦,提高了代码的模块化程度。
同时,AOP还可以实现一些通用的功能,比如日志记录、性能监控、事务管理等,从而减少了重复代码的编写,提高了开发效率。
然而,需要注意的是,在使用AOP切面类注解时,应该遵循一些原则和规范。
首先,切面类的命名应该具有描述性,能够清晰地表达其功能和作用。
其次,切面类的方法应该遵循一定的命名规范,以便其他开发人员能够快速理解其用途。
最后,切面类的通知方法应该尽量保持简洁和高效,避免引入过多的业务逻辑,以免影响程序的性能和可维护性。
总的来说,AOP切面类注解是一种强大的编程技朧,能够有效地解决传统面向对象编程中的一些难题。
AOP切面的使用以及如何在通知上获取切入方法的注解和参数AOP(面向切面编程)是一种编程思想,它将通用横切逻辑(例如日志记录、事务管理、权限控制等)从业务逻辑中分离出来,使得代码更加模块化、可维护和可重用。
AOP通过使用切面(Aspect)来实现这种分离过程,切面可以被应用到多个对象上,从而实现横切逻辑的复用。
在Java中,可以使用AspectJ或Spring AOP等框架来实现AOP。
这些框架都提供了一种方式来声明切面,并将其应用到目标方法上。
通常,切面可以通过注解或配置文件进行声明。
本文将以Spring AOP为例,介绍AOP切面的使用,并说明如何在通知上获取切入方法的注解和参数。
首先,我们需要定义一个切面类(Aspect),用于描述横切逻辑。
切面类通常包含多个通知(Advice),每个通知表示了在目标方法的不同位置执行的操作。
常用的通知类型有:1. 前置通知(Before):在目标方法执行之前执行的操作。
2. 后置通知(After):在目标方法执行之后(包括异常返回)执行的操作。
3. 返回通知(After Returning):在目标方法正常返回之后执行的操作。
4. 异常通知(After Throwing):在目标方法抛出异常之后执行的操作。
5. 环绕通知(Around):在目标方法执行之前和之后都执行的操作。
下面是一个简单的切面类的示例:```javapublic class LoggingAspectpublic void beforeMethod(JoinPoint joinPoint)MethodSignature signature = (MethodSignature)joinPoint.getSignature(;Method method = signature.getMethod(;Loggable loggable = method.getAnnotation(Loggable.class);String message = loggable.value(;//打印日志信息System.out.println("Loggable message: " + message);}public Object aroundMethod(ProceedingJoinPoint joinPoint) throws ThrowableMethodSignature signature = (MethodSignature)joinPoint.getSignature(;Method method = signature.getMethod(;Loggable loggable = method.getAnnotation(Loggable.class);String message = loggable.value(;//执行目标方法前的操作System.out.println("Before executing method: " +method.getName();//执行目标方法Object result = joinPoint.proceed(;//执行目标方法后的操作System.out.println("After executing method: " +method.getName();return result;}```在切面类中,我们通过`JoinPoint`参数来获取切入点的相关信息,如目标方法的签名(通过`getSignature(`方法获取)、方法的注解(通过`getAnnotation(`方法获取)等。
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()事务管理器有很多的实现类:⼀种数据库访问计数有⼀个实现类。
SpringAOP切⾯⽇志Demo配置⽂件⽅式与注解⽅式⼀、配置⽂件⽅式1、配置applicationContext.xml,<bean id="logAopBean"class="mon.aop.LogAop"></bean><aop:config><aop:aspect id="logAspect"ref="logAopBean"><aop:pointcut expression="execution(* com.demo..*(..))" id="allMethod"/><aop:before method="before" pointcut-ref="allMethod" /><aop:after-throwing method="afterThrowing" pointcut-ref="allMethod" /><aop:after-returning method="afterReturn" pointcut-ref="allMethod" /><aop:after method="after" pointcut-ref="allMethod" /></aop:aspect></aop:config>2、⽇志处理类,/*** LogAop.java** Shanghai NTT DATA Synergy Software Co., Ltd. All Rights Reserved.* @author wyl* @date 2016-10-18*/package mon.aop;import ng.JoinPoint;import ng.ProceedingJoinPoint;/*** @author wyl* @Description TODO* @date 2016-10-18**/public class LogAop {public void before(JoinPoint call){String className = call.getTarget().getClass().getName();String methodName = call.getSignature().getName();System.out.println("开始执⾏:"+className+"."+methodName+"()⽅法...");}public void afterThrowing(JoinPoint call){String className = call.getTarget().getClass().getName();String methodName = call.getSignature().getName();System.out.println(className+"."+methodName+"()⽅法抛出了异常...");}public void afterReturn(JoinPoint call){String className = call.getTarget().getClass().getName();String methodName = call.getSignature().getName();System.out.println(className+"."+methodName+"()⽅法正常执⾏结束...");}public void after(JoinPoint call){String className = call.getTarget().getClass().getName();String methodName = call.getSignature().getName();System.out.println(className+"."+methodName+"()最终执⾏步骤(finally)...");}/*//⽤来做环绕通知的⽅法可以第⼀个参数定义为ng.ProceedingJoinPoint类型public Object doAround(ProceedingJoinPoint call) throws Throwable {Object result = null;this.before(call);//相当于前置通知try {result = call.proceed();this.afterReturn(call); //相当于后置通知} catch (Throwable e) {this.afterThrowing(call); //相当于异常抛出后通知throw e;}finally{this.after(call); //相当于最终通知}return result;}*/}⼆、注解⽅式1、配置applicationContext.xml,<bean id="logAspectBean"class="mon.aop.LogAnnotationAspect"></bean> <aop:aspectj-autoproxy/>2、⽇志处理类,/*** LogAnnotationAspect.java** Shanghai NTT DATA Synergy Software Co., Ltd. All Rights Reserved.* @author wyl* @date 2016-10-18*/package mon.aop;import ng.JoinPoint;import ng.ProceedingJoinPoint;import ng.annotation.After;import ng.annotation.AfterReturning;import ng.annotation.AfterThrowing;import ng.annotation.Aspect;import ng.annotation.Before;import ng.annotation.Pointcut;/*** @author wyl* @Description TODO* @date 2016-10-18**/@Aspect //定义切⾯类public class LogAnnotationAspect {@SuppressWarnings("unused")//定义切⼊点,提供⼀个⽅法,这个⽅法的名字就是改切⼊点的id@Pointcut("execution(* com.demo..*(..))")private void allMethod(){}//针对指定的切⼊点表达式选择的切⼊点应⽤前置通知@Before("allMethod()")public void before(JoinPoint call) {String className = call.getTarget().getClass().getName();String methodName = call.getSignature().getName();System.out.println("开始执⾏:"+className+"."+methodName+"()⽅法...");}//访问命名切⼊点来应⽤后置通知@AfterReturning("allMethod()")public void afterReturn(JoinPoint call) {String className = call.getTarget().getClass().getName();String methodName = call.getSignature().getName();System.out.println(className+"."+methodName+"()⽅法正常执⾏结束...");}//应⽤最终通知@After("allMethod()")public void after(JoinPoint call) {String className = call.getTarget().getClass().getName();String methodName = call.getSignature().getName();System.out.println(className+"."+methodName+"()最终执⾏步骤(finally)...");}//应⽤异常抛出后通知@AfterThrowing("allMethod()")public void afterThrowing(JoinPoint call) {String className = call.getTarget().getClass().getName();String methodName = call.getSignature().getName();System.out.println(className+"."+methodName+"()⽅法抛出了异常...");}//应⽤周围通知//@Around("allMethod()")public Object doAround(ProceedingJoinPoint call) throws Throwable{Object result = null;this.before(call);//相当于前置通知try {result = call.proceed();this.afterReturn(call); //相当于后置通知} catch (Throwable e) {this.afterThrowing(call); //相当于异常抛出后通知throw e;}finally{this.after(call); //相当于最终通知}return result;}}。
springAop后置通知AfterReturningAdvice实现原理和代码案例Spring AOP(Aspect-Oriented Programming)是一种面向切面编程的方式,通过在代码中定义切面、通知、切点等元素,可以实现对方法的增强,例如在方法执行之前、之后、抛出异常时等插入特定的代码逻辑。
其中,后置通知(After Returning Advice)是一种在被通知方法成功执行后执行的通知。
后置通知的实现原理是利用动态代理机制,通过代理对象来调用目标对象方法,从而实现对方法的增强。
Spring AOP提供了两种方式来实现后置通知:一种是使用基于配置的方式,另一种是使用基于注解的方式。
下面以基于注解的方式为例,介绍后置通知的实现原理和代码案例。
实现后置通知的步骤如下:1. 创建一个普通的Java类,作为目标对象,其中包含一个被通知的方法。
```javapublic class UserServicepublic void addUser(String username)System.out.println("Add user: " + username);}``````javapublic class LogAspectpublic void afterReturning(JoinPoint joinPoint, Object result)System.out.println("Method executed successfully: " + joinPoint.getSignature(.getName();}``````javapublic class AppConfigpublic UserService userServicreturn new UserService(;}public LogAspect logAspecreturn new LogAspect(;}``````javapublic class UserServiceTestprivate UserService userService;public void testAddUseuserService.addUser("testUser");}```5.运行测试类,控制台输出:```Add user: testUserMethod executed successfully: addUser```代码解析:- returning:定义一个Object类型的参数result,用于接收目标方法的返回值。
详解SpringBootAOP拦截器(Aspect注解⽅式)常⽤⽤于实现拦截的有:Filter、HandlerInterceptor、MethodInterceptor第⼀种Filter属于Servlet提供的,后两者是spring提供的,HandlerInterceptor属于Spring MVC项⽬提供的,⽤来拦截请求,在MethodInterceptor之前执⾏。
实现⼀个HandlerInterceptor可以实现接⼝HandlerInterceptor,也可以继承HandlerInterceptorAdapter类,两种⽅法⼀样。
这个不在本⽂范围,具体使⽤之前已经写过SpringBoot的(SpringMVC的使⽤⼀样,区别只是配置)MethodInterceptor是AOP项⽬中的拦截器,它拦截的⽬标是⽅法,即使不是Controller中的⽅法。
实现MethodInterceptor拦截器⼤致也分为两种,⼀种是实现MethodInterceptor接⼝,另⼀种利⽤Aspect的注解或配置。
关于实现MethodInterceptor接⼝的这种⽅法,还需要在配置⽂件中做配置,在SpringMVC中使⽤还可以,在SpringBoot中使⽤起来似乎没有那么⽅便。
本⽂主要还是说Aspect注解⽅式,个⼈觉得这种⽅法才⽐较灵活,与配置与⼯程整个代码都没有耦合(你添加⼀个类,做⼏个注解就可以⽤了,⽆需在其他地⽅再做什么),更易应⽤。
⾸先为你的SpringBoot项⽬添加maven依赖,让其⽀持aop(其实就是⾃动引⼊aop需要的⼀些jar)在pom.xml中添加依赖:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>然后创建Aspect测试类:package com.shanhy.sboot.aop;import ng.JoinPoint;import ng.annotation.After;import ng.annotation.Aspect;import ng.annotation.Before;import org.springframework.core.annotation.Order;import ponent;@Aspect // FOR AOP@Order(-99) // 控制多个Aspect的执⾏顺序,越⼩越先执⾏@Componentpublic class TestAspect {@Before("@annotation(test)")// 拦截被TestAnnotation注解的⽅法;如果你需要拦截指定package指定规则名称的⽅法,可以使⽤表达式execution(...),具体百度⼀下资料⼀⼤堆 public void beforeTest(JoinPoint point, TestAnnotation test) throws Throwable {System.out.println("beforeTest:" + ());}@After("@annotation(test)")public void afterTest(JoinPoint point, TestAnnotation test) {System.out.println("afterTest:" + ());}}这样就完成了,然后创建⼀个Controller验证⼀下:@RestController@RequestMapping("/test")public class TestController {@TestAnnotation(name="abc")@RequestMapping("/show")public String show() {return "OK";}@RequestMapping("/show2")public String show2() {return "OK2";}}此时我们访问show请求,就会被拦截,控制台会打印输出。
Spring框架——AOP(⾯向切⾯编程)详解1 AOP概述●AOP(Aspect-Oriented Programming,⾯向切⾯编程):是⼀种新的⽅法论,是对传统 OOP(Object-Oriented Programming,⾯向对象编程)的补充。
●AOP编程操作的主要对象是切⾯(aspect),⽽切⾯模块化横切关注点。
●在应⽤AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能应⽤在哪⾥,以什么⽅式应⽤,并且不必修改受影响的类。
这样⼀来横切关注点就被模块化到特殊的类⾥——这样的类我们通常称之为“切⾯”。
●AOP的好处:○每个事物逻辑位于⼀个位置,代码不分散,便于维护和升级○业务模块更简洁,只包含核⼼业务代码2 AOP术语2.1 横切关注点 从每个⽅法中抽取出来的同⼀类⾮核⼼业务。
(抽离到⽅法中处理⾮核⼼业务)2.2 切⾯(Aspect) 封装横切关注点信息的类,每个关注点体现为⼀个通知⽅法。
2.3 通知(Advice) 切⾯必须要完成的各个具体⼯作2.4 ⽬标(Target) 被通知的对象2.5 代理(Proxy) 向⽬标对象应⽤通知之后创建的代理对象2.6 连接点(Joinpoint) 横切关注点在程序代码中的具体体现,对应程序执⾏的某个特定位置。
例如:类某个⽅法调⽤前、调⽤后、⽅法捕获到异常后等。
在应⽤程序中可以使⽤横纵两个坐标来定位⼀个具体的连接点:2.7 切⼊点(pointcut): 定位连接点的⽅式。
每个类的⽅法中都包含多个连接点,所以连接点是类中客观存在的事物。
如果把连接点看作数据库中的记录,那么切⼊点就是查询条件——AOP可以通过切⼊点定位到特定的连接点。
切点通过org.springframework.aop.Pointcut 接⼝进⾏描述,它使⽤类和⽅法作为连接点的查询条件。
3 AspectJ3.1 简介AspectJ:Java社区⾥最完整最流⾏的AOP框架。
SpringBoot使⽤@Aspect注解实现AOPAOP(Aspect Oriented Programming,⾯向切⾯编程)是通过预编译⽅式和运⾏期动态代理实现程序功能的统⼀维护的⼀种技术。
AOP是OOP的延续,是软件开发中的⼀个热点,也是Spring框架中的⼀个重要内容,是函数式编程的⼀种衍⽣范型。
利⽤AOP可以对业务逻辑的各个部分进⾏隔离,从⽽使得业务逻辑各部分之间的耦合度降低,提⾼程序的可重⽤性,同时提⾼了开发的效率。
在Spring AOP中业务逻辑仅仅只关注业务本⾝,将⽇志记录、性能统计、安全控制、事务处理、异常处理等代码从业务逻辑代码中划分出来,从⽽在改变这些⾏为的时候不影响业务逻辑的代码。
相关注解介绍:注解作⽤@Aspect把当前类标识为⼀个切⾯@Pointcut Pointcut是织⼊Advice的触发条件。
每个Pointcut的定义包括2部分,⼀是表达式,⼆是⽅法签名。
⽅法签名必须是public及void 型。
可以将Pointcut中的⽅法看作是⼀个被Advice引⽤的助记符,因为表达式不直观,因此我们可以通过⽅法签名的⽅式为此表达式命名。
因此Pointcut中的⽅法只需要⽅法签名,⽽不需要在⽅法体内编写实际代码。
@Around环绕增强,⽬标⽅法执⾏前后分别执⾏⼀些代码@AfterReturning返回增强,⽬标⽅法正常执⾏完毕时执⾏@Before前置增强,⽬标⽅法执⾏之前执⾏@AfterThrowing异常抛出增强,⽬标⽅法发⽣异常的时候执⾏@After后置增强,不管是抛出异常或者正常退出都会执⾏⼀、添加依赖<!--Spring AOP 切⾯模块 --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId></dependency><!-- SpringBoot 拦截器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency>⼆、编写增强类package com.example.demo.Aspect;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.extern.slf4j.Slf4j;import ng.JoinPoint;import ng.ProceedingJoinPoint;import ng.Signature;import ng.annotation.*;import ng.reflect.SourceLocation;import ponent;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.util.Arrays;@Component@Aspect@Slf4jpublic class LogAspect {private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();@Pointcut("execution(* com.example.demo.Aspect.TestController.doNormal(..))")public void pointCut(){}@Before(value = "pointCut()")public void before(JoinPoint joinPoint){("@Before通知执⾏");//获取⽬标⽅法参数信息Object[] args = joinPoint.getArgs();Arrays.stream(args).forEach(arg->{ // ⼤⼤try {(OBJECT_MAPPER.writeValueAsString(arg));} catch (JsonProcessingException e) {(arg.toString());}});//aop代理对象Object aThis = joinPoint.getThis();(aThis.toString()); //com.xhx.springboot.controller.HelloController@69fbbcdd//被代理对象Object target = joinPoint.getTarget();(target.toString()); //com.xhx.springboot.controller.HelloController@69fbbcdd//获取连接点的⽅法签名对象Signature signature = joinPoint.getSignature();(signature.toLongString()); //public ng.String com.xhx.springboot.controller.HelloController.getName(ng.String) (signature.toShortString()); //HelloController.getName(..)(signature.toString()); //String com.xhx.springboot.controller.HelloController.getName(String)//获取⽅法名(signature.getName()); //getName//获取声明类型名(signature.getDeclaringTypeName()); //com.xhx.springboot.controller.HelloController//获取声明类型⽅法所在类的class对象(signature.getDeclaringType().toString()); //class com.xhx.springboot.controller.HelloController//和getDeclaringTypeName()⼀样(signature.getDeclaringType().getName());//com.xhx.springboot.controller.HelloController//连接点类型String kind = joinPoint.getKind();(kind);//method-execution//返回连接点⽅法所在类⽂件中的位置打印报异常SourceLocation sourceLocation = joinPoint.getSourceLocation();(sourceLocation.toString());//(sourceLocation.getFileName());//(sourceLocation.getLine()+"");//(sourceLocation.getWithinType().toString()); //class com.xhx.springboot.controller.HelloController///返回连接点静态部分JoinPoint.StaticPart staticPart = joinPoint.getStaticPart();(staticPart.toLongString()); //execution(public ng.String com.xhx.springboot.controller.HelloController.getName(ng.String))//attributes可以获取request信息 session信息等ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();(request.getRequestURL().toString()); //http://127.0.0.1:8080/hello/getName(request.getRemoteAddr()); //127.0.0.1(request.getMethod()); //GET("before通知执⾏结束");}/*** 后置返回* 如果第⼀个参数为JoinPoint,则第⼆个参数为返回值的信息* 如果第⼀个参数不为JoinPoint,则第⼀个参数为returning中对应的参数* returning:限定了只有⽬标⽅法返回值与通知⽅法参数类型匹配时才能执⾏后置返回通知,否则不执⾏,* 参数为Object类型将匹配任何⽬标返回值*/@AfterReturning(value = "pointCut()",returning = "result")public void doAfterReturningAdvice1(JoinPoint joinPoint,Object result){("第⼀个后置返回通知的返回值:"+result);}@AfterReturning(value = "pointCut()",returning = "result",argNames = "result")public void doAfterReturningAdvice2(String result){("第⼆个后置返回通知的返回值:"+result);}//第⼀个后置返回通知的返回值:姓名是⼤⼤//第⼆个后置返回通知的返回值:姓名是⼤⼤//第⼀个后置返回通知的返回值:{name=⼩⼩, id=1}/*** 后置异常通知* 定义⼀个名字,该名字⽤于匹配通知实现⽅法的⼀个参数名,当⽬标⽅法抛出异常返回后,将把⽬标⽅法抛出的异常传给通知⽅法;* throwing:限定了只有⽬标⽅法抛出的异常与通知⽅法相应参数异常类型时才能执⾏后置异常通知,否则不执⾏,* 对于throwing对应的通知⽅法参数为Throwable类型将匹配任何异常。
aop获取方法参数的注解摘要:1.Annotation Overviewmon Usage of Annotations in Java3.Advantages and Disadvantages of Using Annotations4.Example of Using @RequestParam Annotation5.Conclusion正文:【1.Annotation Overview】在Java编程语言中,注解(Annotations)是一种元数据,可以用于为代码添加额外的信息。
注解通常被用于修饰类、方法、字段等元素,以便在编译时或运行时被其他代码(如框架或第三方库)读取和处理。
在本篇教程中,我们将重点讨论如何使用注解获取方法参数的值。
【mon Usage of Annotations in Java】在Java中,有几个常用的注解,如@RequestParam、@PathVariable、@Controller、@Service等。
这些注解在框架(如Spring)中起着重要作用,帮助开发者更好地组织和管理代码。
在本教程中,我们将以@RequestParam注解为例,介绍如何在方法参数中使用注解。
【3.Advantages and Disadvantages of Using Annotations】使用注解有以下优点:1.提高代码的可读性:注解使代码更具描述性,有助于理解代码的功能和用途。
2.提高代码的复用性:通过注解,可以定义一组通用的行为,然后在不同的场景中重复使用。
3.解耦:注解可以将逻辑与实现分离,便于后期修改和扩展。
然而,注解也存在一些缺点:1.增加代码的复杂性:过多的注解可能导致代码过于冗余,难以维护。
2.学习成本:使用注解需要额外学习注解的语法和用法,对于初学者来说可能有一定门槛。
【4.Example of Using @RequestParam Annotation】以下是一个使用@RequestParam注解的简单示例:```java@Controllerpublic class MyController {@GetMapping("/hello")public String sayHello(@RequestParam("name") String name) { return "Hello, " + name + "!";}}```在这个例子中,当用户访问`/hello`接口时,浏览器将发送一个包含`name`参数的GET请求。
Spring系列之AOP实现的两种⽅式Spring只⽀持XML⽅式⽽没有实现注解的⽅式(也叫AspectJ⽅式)的AOP,所以要使⽤@Aspect注解,只能引⼊AspectJ相关的 jar 包:aopalliance-1.0.jar 和 aspectjweaver.jarSpring的配置⽂件 applicationContext.xml 中引⼊context、aop对应的命名空间;配置⾃动扫描的包,同时使切⾯类中相关⽅法中的注解⽣效,需⾃动地为匹配到的⽅法所在的类⽣成代理对象。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:aop="/schema/aop"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd/schema/aop /schema/aop/spring-aop-4.0.xsd/schema/context /schema/context/spring-context-4.0.xsd"><!-- 配置⾃动扫描的包 --><context:component-scan base-package="com.qcc.beans.aop"></context:component-scan><!-- ⾃动为切⾯⽅法中匹配的⽅法所在的类⽣成代理对象。
--><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>AOP常⽤的实现⽅式有两种,1、采⽤声明的⽅式来实现(基于XML),2、是采⽤注解的⽅式来实现(基于AspectJ)。
aop切面中或获取自定义注解中的参数AOP(面向切面编程)是一种编程思想,它允许开发人员在应用程序的不同层次上插入代码,以便在运行时对其进行拦截和修改。
在AOP中,切面是一组跨越多个类和方法的通用功能,例如日志记录、性能测量、安全性等。
在切面中,我们可以使用自定义注解来传递参数,以便更好地控制切面的行为。
下面是一些有关在AOP切面中或获取自定义注解中的参数的技巧:1. 使用@Around注解@Around注解是Spring AOP中最强大的注解之一。
它允许我们在方法执行之前和之后拦截方法调用,并在必要时修改方法参数和返回值。
在@Around注解中,我们可以使用ProceedingJoinPoint参数访问方法参数和方法签名,并使用它们来执行额外的操作。
2. 使用@Pointcut注解@Pointcut注解用于定义一个切点,即一组匹配的方法或类。
在@Pointcut注解中,我们可以使用自定义注解来指定要匹配的方法或类,并使用它们来定义切点。
例如,我们可以使用@Pointcut注解来定义一个切点,以便在所有被@Loggable注解的方法中添加日志记录。
3. 使用@Aspect注解@Aspect注解用于定义一个切面,即一组跨越多个类和方法的通用功能。
在@Aspect注解中,我们可以使用自定义注解来指定要匹配的方法或类,并使用它们来定义切面。
例如,我们可以使用@Aspect注解来定义一个切面,以便在所有被@Cacheable注解的方法中添加缓存逻辑。
4. 使用@Annotation注解@Annotation注解用于定义一个自定义注解,并将其与切面或切点相关联。
在@Annotation注解中,我们可以使用元注解@Target和@Retention来指定自定义注解的作用域和生命周期,并使用元注解@Inherited来指定自定义注解是否可以被子类继承。
例如,我们可以使用@Annotation注解来定义一个@Loggable注解,并将其与一个日志记录切面相关联。
1.建立工程后,首先所需要的导入jar
---------------------------------------------------------------------------------------------------------------------- 2.导入jar后,就该配置xml 注意下面红色的配置
<?xml version="1.0"encoding="UTF-8"?>
<!-- 需要对下面命名空间配置 -->
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:aop="/schema/aop"
xmlns:jms="/schema/jms"
xmlns:context="/schema/context"
xsi:schemaLocation="
/schema/beans
/schema/beans/spring-beans-2.5.xsd /schema/jms
/schema/jms/spring-jms-2.5.xsd
/schema/aop
/schema/aop/spring-aop-2.5.xsd
/schema/context
/schema/context/spring-context-2.5. xsd">
<!-- 打开AOP注解配置(支持) -->
<aop:aspectj-autoproxy/>
</beans>
----------------------------------------------------------------------------------------------------------------------
3.创建接口
package spring.aop.service;
public interface PeopleService {
public void save(String name);
public void update(Integer id,String name);
public String getPeopleName(Integer id);
}
---------------------------------------------------------------------------------------------------------------------- 4.实现累(业务bean)
package spring.aop.impl;
import spring.aop.service.PeopleService;
public class PeopleServiceBean implements PeopleService{
@Override
public String getPeopleName(Integer id) {
System.out.println("this is getPeopleName method");
return"XXX";
}
@Override
public void save(String name) {
System.out.println("this is save method");
}
@Override
public void update(Integer id, String name) {
System.out.println("this is update method");
}
}
5.接下来了解下注解符号
1.第一步首先声明切面类
package spring.aop.interceptor;
import ng.annotation.Aspect;
@Aspect
public class MyInterceptor {
2.声明切入点 ---拦截
@Pointcut("execution(* spring.aop.annotation..*.*(..))")
public void anyMethod(){}//设置切入点(也就是说这个anyMethod()方法来代替切入的方法)
//切入点:第一个*指的是对于任意返回类型,接下来spring.aop.annotation 包
..指的是:本包或者字包里面,*这里指的是任意类,然后接下来*指的是任意方法(..)指的是任意参数
3.设置前置通知
@Before("anyMethod()")
//拦截方法,在执行前先执行anyMethod()
public void doAccessCheck(String name){
//这个是前置通知的方法,在调用bean实例方法前
System.out.println("这是前置通知"+name);
}
}
6.编写测试类
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.AbstractApplicationContext; import
org.springframework.context.support.ClassPathXmlApplicationContex t;
import spring.aop.service.PeopleService;
public class Junit4_test {
@Test
public void test(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
PeopleService
peopleService=(PeopleService)ctx.getBean("peopleService");
peopleService.save("xixi");
// peopleService.getPeopleName(11);
}
}
实验总结:
过程中遇到问题
org.springframework.beans.factory.BeanDefinitionStoreException: IOException
该问题是由于建立该项目是Java项目,beans.xml直接放在根目录里面,没有放在src里面,导致出错,如果是web项目是放在webroot里面。