目录
4.方法参数校验
SpingAOP介绍
Schema-based方式实现AOP
4.方法参数校验
Spring框架提供了一种校验方法参数的方法,在调用一个方法传入参数后,会判断参数是否满足数据校验。如果满足方法执行,如果不满足:不执行方法,报异常。这和上面是不一样的。并且不需要使用 LocalValidatorFactoryBean 。
方法参数校验的核心有三点:
1、IoC容器中必须有MethodValidationPostProcessor这个Bean。默认没有,需要我们手动配置
2、需要进行方法校验的类上需要有@Validated注解
3、需要校验的方法参数前面需要有@Valid注解
4.1 新建类,添加校验注解
我们还是用Student类,并在属性中添加校验
@Data
public class Student {@NotBlankprivate String name;@Positiveprivate int age;
}
4.2 新建类,添加方法
新建com.tong.validation.StudentServiceImpl类,并添加注解
@Validated // 重要
public class StudentServiceImpl{public void student(@Valid Student stu){// @Valid 重要System.out.println("执行了这个方法");}
}
4.3 新建配置文件
新建配置文件applicationContext-methodvalidation.xml 在配置文件中配置MethodValidationPostProcessor和StudentServiceImpl的Bean。 此功能和LocalValidatorFactoryBean无关,不需要配置LocalValidatorFactoryBean的Bean。
<bean id="studentServiceImpl" class="com.tong.validation.StudentServiceImpl"></bean><bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcess
or"></bean>
4.4 新建测试类
新建com.tong.test.ValidationMethodTest测试类
@SpringJUnitConfig
@ContextConfiguration("classpath:applicationContext-methodvalidation.xml")
public class ValidationMethodTest {@AutowiredStudentServiceImpl studentService;@Testvoid test(){Student stu = new Student();studentService.student(stu);}
}
4.5 查看运行效果
在控制台报异常。
jakarta.validation.ConstraintViolationException: student.arg0.age: 必须是正数,
student.arg0.name: 不能为空
4.6 校验通过写法
给Student对象的属性设置上值,让校验通过。重新运行后,发现方法成功被调用。
@SpringJUnitConfig
@ContextConfiguration("classpath:applicationContext-methodvalidation.xml")
public class ValidationMethodTest {@AutowiredStudentServiceImpl studentService;@Testvoid test(){Student stu = new Student();stu.setName("smallming");//新加stu.setAge(16);// 新加studentService.student(stu);}
}
SpingAOP介绍
1.SpringAOP介绍
AOP(Aspect-oriented Programming,面向切面编程)并不是Spring框架提出的。而是AOP联盟组织的 一套规范。Spring AOP属于对AOP规范的一个具体实现。 我们先看看Spring官方对Spring AOP的解释。
官方说明:
翻译含义:
面向切面编程 (AOP) 通过提供另一种思考程序结构的方式来补充面向对象编程 (OOP)。OOP 中模块化的关键单位是类,而 AOP 中模块化的单位是切面。切面能够实现跨越多种类型和对象的关注点(例如事务 管理)的模块化.(这种关注点在 AOP 文献中通常被称为“横切”关注点。) Spring 的关键组件之一是 AOP 框架。虽然 Spring IoC 容器不依赖于 AOP(意味着如果您不想使用 AOP,则不需要使用 AOP),但 AOP 补充了 Spring IoC 以提供一个非常强大的中间件解决方案。
下面对上面官方解释的总结:官方在强调AOP时强调了下面几点:
1. AOP 叫做面向切面编程
2. AOP 是对OOP的补充
3. AOP的核心是切面
4. AOP是依赖IoC
5. AOP可以让多个类型和对象以模块化的方式形成横切面。
所以AOP的解释:AOP是面向切面编程。可以对程序中方法进行扩展,且扩展内容和目标方法是松耦合 的(无论对目标方法还是对客户端,扩展后都是无感知的)、模块化的。
想要把AOP解释清楚,就必须把AOP中的专业术语搞清楚。
Aspect:切面。即join point + Advice
join point: 切入点。就是我们平时说的目标方法,或说对哪个方法做扩展,做增强。
Advice:通知,增强内容。
Pointcut:切点。就是表达式,通过表达式说明哪些方法是join point
AOP Proxy:代理。Spring支持JDK动态代理和cglib动态代理两种方式,可以通过proxy-target-class=true把默认的JDK动态代理修改为Cglib动态代理。
Weaving:织入。织入就是把Advice添加到join point的过程。
在实际开发中AOP主要应用在Service层。
Schema-based方式实现AOP
1.实现AOP的两种方式
在Spring中提供了两种方式实现AOP:
- Schema-based:所有的通知都需要实现特定类型的接口。
- AspectJ:可以使用普通Java类结合特定的配置标签实现通知。
无论使用哪种方式在项目中都需要导入spring-aop和aspectjweaver两个依赖。
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.6</version>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.19</version>
</dependency>
2.在Schema-based方式中通知的分类
- 前置通知:在切入点之前执行的增强功能。通知需要实现MethodBeforeAdvice接口
- 后置通知:在切入点之后执行的增强功能。通知需要实现AfterReturningAdvice接口
- 环绕通知:一个方法包含了前置通知和后置通知的功能。通知需要实现MethodInterceptor接口
- 异常通知:如果切入点中出现了异常(绝对不能try...catch解决了异常)就会触发异常通知。通知 需要实现ThrowsAdvice接口。
3. 前置通知
前置通知是在切入点之前执行的增强。 在项目中保证有Spring框架最基本环境依赖以外,还需要打入aspectj依赖
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.6</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.19</version></dependency><!-- 单元测试 --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.0.6</version></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.9.2</version><scope>test</scope></dependency><!-- lombok 支持 @Data等注解 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version><scope>provided</scope></dependency>
</dependencies>
3.1 新建通知类
新建com.bjsxt.advice.MyBefore。
MethodBeforeAdvice接口中必须重写before方法,方法中三个参数:
- method:切入点方法对象
- args:切入点方法参数
- target:切入点方法所在的对象
package com.tong.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyBefore implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("前置通知");}
}
3.2 配置切面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><context:component-scan base-package="com.tong.mapper,com.tong.service.impl"> </context:component-scan><bean id="mybefore" class="com.tong.advice.MyBefore"></bean><aop:config><!-- 切入点是固定语法:execution(* 方法的全限定路径带有参数) --><!-- 无参方法:test()--><!-- 有参方法:test(int,java.lang.String)--><!-- 如果希望把所有叫做test的方法都匹配上,不考虑参数test(..)--><!-- 全限定路径的层数绝对不能少,但是如果希望对类或包做统配使用*--><!-- com.tong.service.impl.*.*(..)--><aop:pointcut id="mypoint" expression="execution(* com.tong.service.impl.PeopleServiceImpl.test())"/><aop:advisor advice-ref="mybefore" pointcut-ref="mypoint"></aop:advisor></aop:config>
</beans>
4. 后置通知
后置通知是在切入点之后执行的增强。
4.1 新建通知类
新建com.bjsxt.advice.MyAfter。 AfterReturningAdvice接口中必须重写afterReturning方法,方法中四个参数:
- returnValue:返回值
- method:切入点方法对象
- args:切入点方法参数
- target:切入点方法所在的对象
package com.tong.advice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class MyAfter implements AfterReturningAdvice {@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args,Object target) throws Throwable {System.out.println("后置通知");}
}
4.2 配置切面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><context:component-scan base-package="com.tong.mapper,com.tong.service.impl"> </context:component-scan><bean id="mybefore" class="com.tong.advice.MyBefore"></bean><!-- 配置后置通知bean --><bean id="myafter" class="com.tong.advice.MyAfter"></bean><aop:config><aop:pointcut id="mypoint" expression="execution(* com.tong.service.impl.PeopleServiceImpl.test())"/><aop:advisor advice-ref="mybefore" pointcut-ref="mypoint"></aop:advisor><!-- 织入后置通知 --><aop:advisor advice-ref="myafter" pointcut-ref="mypoint"></aop:advisor></aop:config>
</beans>
5. 环绕通知
环绕通知可以实现前置通知和后置通知两种功能。
5.1 新建通知类
新建com.tong.advice.MyAround。
MethodInterceptor接口中必须重写invoke方法,方法中参数:
- invocation:方法调用器。通过invocation可以proceed()方法调用执行点。
package com.tong.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class MyAround implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("环绕通知-前置增强");Object result = invocation.proceed();// 执行切入点System.out.println("环绕通知-后置增强");return result;}
}
5.2 配置切面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><context:component-scan base-package="com.tong.mapper,com.tong.service.impl"> </context:component-scan><bean id="mybefore" class="com.tong.advice.MyBefore"></bean><bean id="myafter" class="com.tong.advice.MyAfter"></bean><!-- 配置环绕通知bean --><bean id="myaround" class="com.tong.advice.MyAround"></bean><aop:config><aop:pointcut id="mypoint" expression="execution(* com.tong.service.impl.PeopleServiceImpl.test())"/><!-- 只织入环绕,没有织入前置通知和后置通知。 --><aop:advisor advice-ref="myaround" pointcut-ref="mypoint"></aop:advisor></aop:config>
</beans>