AOP
1.介绍
Aspect Oriented Programming 面向切面编程,将程序中的相同业务逻辑进行横向隔离,将重复的业务逻辑抽取到一个独立的模块。、
- 连接点Joinpoint:程序执行过程中某个特定的节点
- 通知Advice:在目标类连接点上执行的代码,有around,before等类型
- 切点Pointcut:匹配连接点的断言,AOP通过其定位到连接点。
- 目标对象Target:通知所作用的目标类。
- 引介Introduction: 特殊的通知,为类添加属性和方法。动态地为业务类添加接口的实现逻辑。
- 切面Aspect: 对系统中的横切关注点逻辑进行模块化封装的AOP概念实体。
- 织入Weaving: 将通知添加到目标类具体连接点的过程,在编译,类加载,运行时完成,Spring动态代理织入,AspectJ编译期和类装载器织入。
- 代理Proxy:目标类被织入增强后产生的结果类,融合了原类和增强的逻辑。
2.实现机制
2.1 JDK动态代理
JDK代理只能为接口创建代理实例
- LoginService接口
public interface LoginService {
public void login();
}
- LoginServiceImpl
public class LoginServiceImpl implements LoginService{
@Override
public void login() {
System.out.println("Login");
}
}
- PerformHandler类
public class PerformHandler implements InvocationHandler {
private Object target;
public PerformHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强的方法
System.out.println("start");
//执行被代理类的原方法
Object invoke = method.invoke(target, args);
System.out.println("end");
return invoke;
}
}
- Test类
@Test
public void fun(){
LoginService loginService = new LoginServiceImpl();
//通过Proxy生成代理对象
PerformHandler performHandler = new PerformHandler(loginService);
loginService = (LoginService) Proxy.newProxyInstance(loginService.getClass().getClassLoader(),
loginService.getClass().getInterfaces(),performHandler);
loginService.login();
}
2.2 CGLib动态代理
CGLib动态代理为类创建实例 底层字节码技术 继承的方式实现
依靠Enhancer类创建代理实例 MethodInterceptor接口织入方法
- CglibProxy
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
//生成代理对象
public Object getProxy(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
//回调方法 拦截目标类所有方法调用
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("start");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("end");
return invoke;
}
}
- Test类
@Test
public void funG(){
CglibProxy cglibProxy = new CglibProxy();
//创建代理对象
LoginServiceImpl loginService = (LoginServiceImpl) cglibProxy.getProxy(LoginServiceImpl.class);
loginService.login();
}
3.实现方法
3.1 XML
- spring.xml
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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 name="loginService" class="service.LoginServiceImpl"></bean>
<bean name = "xmlAdvice" class="service.XmlAdvice"></bean>
<!-- Spring Aop-->
<aop:config>
<!-- 切点-->
<aop:pointcut id="pointcut" expression="execution(* service.LoginServiceImpl.*(..))"/>
<!-- 切面-->
<aop:aspect ref="xmlAdvice">
<!-- 前置-->
<aop:before method="before" pointcut-ref="pointcut"></aop:before>
<!-- 返回-->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"></aop:after-returning>
<!-- 环绕-->
<aop:around method="around" pointcut-ref="pointcut"></aop:around>
<!-- 异常-->
<aop:after-throwing method="afterException" pointcut-ref="pointcut"></aop:after-throwing>
<!-- 后置-->
<aop:after method="after" pointcut-ref="pointcut"></aop:after>
</aop:aspect>
</aop:config>
</beans>
- Test类
@Test
public void funXml(){
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring1.xml");
LoginService loginService = context.getBean("loginService", LoginService.class);
loginService.login();
}
3.2 注解
- Spring.xml 修改
<bean name="annoAdvice" class="service.AnnoAdvice"></bean>
<!-- 自动动态代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean name="loginService" class="service.LoginServiceImpl"></bean>
- AnnoAdvice类
@Aspect
public class AnnoAdvice {
//切点
@Pointcut("execution(* service.LoginServiceImpl.*(..))")
public void pointcut(){
}
@Before("pointcut()")
public void before(){
System.out.println("before");
}
//后置通知 异常不执行
@AfterReturning("pointcut()")
public void afterReturning(){
System.out.println("afterReturning");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable{
System.out.println("around start");
Object object = point.proceed();
System.out.println("around end");
return object;
}
@AfterThrowing("pointcut()")
public void afterException(){
System.out.println("Exception");
}
@After("pointcut()")
public void after(){
System.out.println("after");
}
}
4.应用
4.1 性能监控
- Service1
public class Service1 {
public void service() throws Exception{
System.out.println("service");
Thread.sleep(1000);
}
}
- Record类:记录执行信息
public class Record {
private String className;
private String methodName;
private Date recordTime;
private Long expendTime;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Date getRecordTime() {
return recordTime;
}
public void setRecordTime(Date recordTime) {
this.recordTime = recordTime;
}
public Long getExpendTime() {
return expendTime;
}
public void setExpendTime(Long expendTime) {
this.expendTime = expendTime;
}
@Override
public String toString() {
return "Record{" +
"className='" + className + '\'' +
", methodName='" + methodName + '\'' +
", recordTime=" + recordTime +
", expendTime=" + expendTime +
'}';
}
}
- RecordAspect类
@Aspect
public class RecordAspect {
@Pointcut("execution(* applicationAop.Service* .*(..))")
public void record(){
}
@Around("record()")
public Object recordTime(ProceedingJoinPoint point) throws Throwable{
String className = point.getTarget().getClass().getName();
String methodName = point.getSignature().getName();
//方法执行时间
long startTime = System.currentTimeMillis();
Object result = point.proceed();
long time = System.currentTimeMillis() - startTime;
Record record = new Record();
record.setExpendTime(time);
record.setClassName(className);
record.setMethodName(methodName);
record.setRecordTime(new Date());
System.out.println(record);
return result;
}
}
- xml配置
<bean name="service1" class="applicationAop.Service1"></bean>
<bean name="recordAspect" class="applicationAop.RecordAspect"></bean>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- Test类
@Test
public void test() throws Exception{
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring1.xml");
Service1 service1 = context.getBean("service1",Service1.class);
service1.service();
}
4.2 异常监控
- MyException类
public class MyException extends Exception{
private static final long serialVersionUID = 1l;
private String msg;
public MyException(String msg) {
super();
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
- Service2
public class Service2 {
public void service() throws Exception{
System.out.println("service2");
if(true){
throw new MyException("true");
} else {
System.out.println(false);
}
}
}
- Message类
public class Message {
private String className;
private String methodName;
private Date recordTime;
private String exceptionMsg;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Date getRecordTime() {
return recordTime;
}
public void setRecordTime(Date recordTime) {
this.recordTime = recordTime;
}
public String getExceptionMsg() {
return exceptionMsg;
}
public void setExceptionMsg(String exceptionMsg) {
this.exceptionMsg = exceptionMsg;
}
@Override
public String toString() {
return "Message{" +
"className='" + className + '\'' +
", methodName='" + methodName + '\'' +
", recordTime=" + recordTime +
", exceptionMsg='" + exceptionMsg + '\'' +
'}';
}
}
- MessageAspect
@Aspect
public class MessageAspect {
@Pointcut("execution(* applicationAop.Service* .*(..))")
public void exceptionMsg(){
}
@Around("exceptionMsg()")
public Object msgMethod(ProceedingJoinPoint point) throws Throwable{
String className = point.getTarget().getClass().getName();
String methodName = point.getSignature().getName();
try {
return point.proceed();
}catch (MyException e){
Message message = new Message();
message.setClassName(className);
message.setMethodName(methodName);
message.setRecordTime(new Date());
message.setExceptionMsg(e.getMsg());
System.out.println(message);
}
return null;
}
}
- xml配置
<bean name="service2" class="applicationAop.Service2"></bean>
<bean name="mmessageAspect" class="applicationAop.MessageAspect"></bean>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-Test类
@Test
public void test1() throws Exception{
ApplicationContext context = new ClassPathXmlApplicationContext("config/spring1.xml");
Service2 service2 = context.getBean("service2",Service2.class);
service2.service();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律