Spring中的可插拔组件技术
Spring AOP
- Spring AOP——Aspect Oriented Programming 面向切面编程
- AOP 的做法是将通用的、与业务无关的功能抽象封装为切面层
- 切面可配置在目标方法执行前后,做到即插即用
不修改源码对程序功能进行拓展
AoP的关键概念
Spring AoP 与AspectJ的关系
- Eclipse AspectJ,一种基于Java平台的面向切面编程的语言
- Spring AoP 使用AspectJWeaver 实现 类与方法匹配
- Spring AOP 利用代理模式实现对象运行时功能拓展
几个重要概念
AOP配置过程
- 依赖AaspectJ
- 实现切面类和方法
- 配置Aspect Bean
- 定义PointCut
- 配置Aadvice
JoinPoint核心方法
注解 | 说明 |
---|---|
Object getTarget() | 获取IoC容器内目标对象 |
Signature getSignature() | 获取目标方法 |
Object[] getArgs() | 获取目标方法参数 |
PointCut 切点表达式
五种通知类型
xml配置如下:
<aop:config><!-- pointcut 切点,使用excution表达式描述切面的作用范围--><!-- execution(public * com.imooc..*.*(..))表达式说明切面作用在com.imooc包下的所有类的所有方法上 --><aop:pointcut id="pointcut" expression="execution(public * com.imooc..*Service.*(..))"/><aop:aspect ref="methodAspect"><!-- before 通知,代表在目标方法之前运行methodAspect.printExecutionTime--><aop:before method="printExecutionTime" pointcut-ref="pointcut"/><aop:after-returning method="doAfterReturning" returning="ret" pointcut-ref="pointcut"/><aop:after method="doAfter" pointcut-ref="pointcut"/><aop:after-throwing method="doAfterThrowing" throwing="exception" pointcut-ref="pointcut"/></aop:aspect></aop:config>
利用AOP 进行方法性能筛查
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<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"xmlns="http://www.springframework.org/schema/beans"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="userDao" class="com.imooc.spring.aop.dao.UserDao"/><bean id="employeeDao" class="com.imooc.spring.aop.dao.EmployeeDao"/><bean id="userService" class="com.imooc.spring.aop.service.UserService"><property name="userDao" ref="userDao"/></bean><bean id="employeeService" class="com.imooc.spring.aop.service.EmployeeService"><property name="employeeDao" ref="employeeDao"/></bean><!--<bean id="methodAspect" class="com.imooc.spring.aop.aspect.MethodAspect"></bean><aop:config><!– pointcut 切点,使用excution表达式描述切面的作用范围–><!– execution(public * com.imooc..*.*(..))表达式说明切面作用在com.imooc包下的所有类的所有方法上 –><aop:pointcut id="pointcut" expression="execution(public * com.imooc..*Service.*(..))"/><aop:aspect ref="methodAspect"><!– before 通知,代表在目标方法之前运行methodAspect.printExecutionTime–><aop:before method="printExecutionTime" pointcut-ref="pointcut"/><aop:after-returning method="doAfterReturning" returning="ret" pointcut-ref="pointcut"/><aop:after method="doAfter" pointcut-ref="pointcut"/><aop:after-throwing method="doAfterThrowing" throwing="exception" pointcut-ref="pointcut"/></aop:aspect></aop:config>--><bean id="methodChecker" class="com.imooc.spring.aop.aspect.MethodChecker"/><aop:config><aop:pointcut id="pointcut" expression="execution(* com.imooc..*.*(..))"/><aop:aspect ref="methodChecker"><aop:around method="check" pointcut-ref="pointcut"/></aop:aspect></aop:config>
</beans>
methodChecker:
package com.imooc.spring.aop.aspect;import org.aspectj.lang.ProceedingJoinPoint;import java.text.SimpleDateFormat;
import java.util.Date;/*** todo {类简要说明}** @Author wangw* @Date 2022/12/1 22:59* @Version 1.0*/
public class MethodChecker {// proceedingJoinPoint是原有JoinPoint的升级,在原有功能基础上,还能控制目标方法是否执行public Object check(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {try {long startTime = System.currentTimeMillis();Object ret = proceedingJoinPoint.proceed();long endTime = System.currentTimeMillis();long duration =endTime-startTime;if (duration>=1000){SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss SSS");String className = proceedingJoinPoint.getTarget().getClass().getName();String methodName =proceedingJoinPoint.getSignature().getName();Object[] args =proceedingJoinPoint.getArgs();String now = sdf.format(new Date());System.out.println("======"+now+":"+className+"."+methodName+"."+"("+duration+")ms==============");}return ret;} catch (Throwable e) {throw e;}}
}
基于注解开发SpringAOP
Spring AOP 实现原理
- Spring 基于代理模式实现动态功能拓展,包含两种形式
- 目标类拥有接口,通过JDK动态代理实现功能拓展
- 目标类没有接口,通过CGLib实现功能拓展
代理模式
- 代理模式通过代理对象对原对象实现功能拓展
(静态代理 是指必须手动创建按代理类的代理模式使用方式)
JDK动态代理
private Object targetObj;public ProxyInvocationHandle(Object targetObj){this.targetObj =targetObj;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("前置执行方法");Object ret = method.invoke(targetObj,args);System.out.println("后置方法");return ret;}public static void main(String[] args) {UserService userService = new UserServiceImpl();ProxyInvocationHandle proxyInvocationHandle = new ProxyInvocationHandle(userService);UserService userServiceProxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),proxyInvocationHandle);userServiceProxy.createUser();EmployeeService employeeService =new EmployeeServiceImpl();ProxyInvocationHandle proxyInvocationHandleProxy = new ProxyInvocationHandle(employeeService);EmployeeService employeeServiceProxy = (EmployeeService) Proxy.newProxyInstance(employeeService.getClass().getClassLoader(),employeeService.getClass().getInterfaces(),proxyInvocationHandleProxy);employeeServiceProxy.say();}
public interface EmployeeService {public void createNewEmployee();
}
public class EmployeeServiceImpl implements EmployeeService{public void say() {System.out.println("hello");}
}
CGLib
使用代理时如果没有接口,则使用CGLib