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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://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