转载

Spring 从入门到入土——AOP 就这么简单!| 原力计划

Spring 从入门到入土——AOP 就这么简单!| 原力计划

Spring 从入门到入土——AOP 就这么简单!| 原力计划 作者|  冢狐

责编 | 夕颜

出品 | CSDN博客

Spring 从入门到入土——AOP 就这么简单!| 原力计划

什么是AOP?

面向切面编程(Aspect Oriented Programming),通过预编译的方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型,利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各个部分的耦合度降低,提高程序的可重用性,同时提高了开发效率。

Spring 从入门到入土——AOP 就这么简单!| 原力计划

AOP在Spring中的作用

  • 提供声明式事务;允许用户自定义切面

核心名词

  • 横切关注点:横跨应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的地方,就是横切关注点,如:日志、安全、缓存、事务

  • 切面:横切关注点被模块化的特性对象,即:它是一个类

  • 通知:切面必须要完成的工作。即它是类中的一个方法

  • 目标:被通知对象

  • 代理:向目标对象应用通知以后创建的对象。

  • 切入点:切面通知执行的“地点的定义

  • 连接点:与切入点匹配的执行点

Spring中支持的五种类型的Advice

Spring 从入门到入土——AOP 就这么简单!| 原力计划

即Aop在不改变原有代码的情况下,去增加新的功能。

Spring 从入门到入土——AOP 就这么简单!| 原力计划

使用Spring实现Aop

使用AOP,需要导入一个依赖包

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjweaver</artifactId>

<version>1.9.4</version>

</dependency>

第一种方式——通过Spring API实现

业务接口和实现类

public interface UserService {



public void add();



public void delete();



public void update();



public void search();



}

public class UserServiceImpl implements UserService{



@Override

public void add() {

System.out.println("增加用户");

}



@Override

public void delete() {

System.out.println("删除用户");

}



@Override

public void update() {

System.out.println("更新用户");

}



@Override

public void search() {

System.out.println("查询用户");

}

}

增强类

  • 前置增强

public class Log implements MethodBeforeAdvice {



//method : 要执行的目标对象的方法

//objects : 被调用的方法的参数

//Object : 目标对象

@Override

public void before(Method method, Object[] objects, Object o) throws Throwable {

System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了");

}

}

  • 后置增强

public class AfterLog implements AfterReturningAdvice {

//returnValue 返回值

//method被调用的方法

//args 被调用的方法的对象的参数

//target 被调用的目标对象

@Override

public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

System.out.println("执行了" + target.getClass().getName()

+"的"+method.getName()+"方法,"

+"返回值:"+returnValue);

}

}

去Spring的文件中注册,并实现aop切入实现

<?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:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd">



<!--注册bean-->

<bean id="userService" class="com.zhonghu.service.UserServiceImpl"/>

<bean id="log" class="com.zhonghu.log.Log"/>

<bean id="afterLog" class="com.zhonghu.log.AfterLog"/>



<!--aop的配置-->

<aop:config>

<!--切入点 expression:表达式匹配要执行的方法-->

<aop:pointcut id="pointcut" expression="execution(* com.zhonghu.service.UserServiceImpl.*(..))"/>

<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->

<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>

<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>

</aop:config>



</beans>

测试

public class MyTest {

@Test

public void test(){

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

UserService userService = (UserService) context.getBean("userService");

userService.search();

}

}

Aop的重要性:很重要,一定要理解其中的思路

Spring的Aop就是将公共的业务(日志、安全)和领域业务结合起来,当执行领域业务时,将会把公共业务加起来,实现公共业务的重复利用,领域业务更加纯粹,程序员只需要专注领域业务。

其本质还是动态代理

第二种方式:自定义类来实现Aop

目标业务不变依旧是userServiceImpl

切入类

public class DiyPointcut {



public void before(){

System.out.println("---------方法执行前---------");

}

public void after(){

System.out.println("---------方法执行后---------");

}


}

去spring中配置

<!--第二种方式自定义实现-->

<!--注册bean-->

<bean id="diy" class="com.zhonghu.config.DiyPointcut"/>



<!--aop的配置-->

<aop:config>

<!--第二种方式:使用AOP的标签实现-->

<aop:aspect ref="diy">

<aop:pointcut id="diyPonitcut" expression="execution(* com.zhonghu.service.UserServiceImpl.*(..))"/>

<aop:before pointcut-ref="diyPonitcut" method="before"/>

<aop:after pointcut-ref="diyPonitcut" method="after"/>

</aop:aspect>

</aop:config>

测试

public class MyTest {

@Test

public void test(){

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

UserService userService = (UserService) context.getBean("userService");

userService.add();

}

}

第三种方式——使用注解

注解实现的增强类

package com.zhonghu.config;



import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;



@Aspect

public class AnnotationPointcut {

@Before("execution(* com.zhonghu.service.UserServiceImpl.*(..))")

public void before(){

System.out.println("---------方法执行前---------");

}



@After("execution(* com.zhonghu.service.UserServiceImpl.*(..))")

public void after(){

System.out.println("---------方法执行后---------");

}



@Around("execution(* com.zhonghu.service.UserServiceImpl.*(..))")

public void around(ProceedingJoinPoint jp) throws Throwable {

System.out.println("环绕前");

System.out.println("签名:"+jp.getSignature());

//执行目标方法proceed

Object proceed = jp.proceed();

System.out.println("环绕后");

System.out.println(proceed);

}

}

在spring配置文件中,注册bean,并增加支持注解的配置

<!--第三种方式:注解实现-->

<bean id="annotationPointcut" class="com.zhonghu.config.AnnotationPointcut"/>

<aop:aspectj-autoproxy/>

aop:aspectj-autoproxy:说明

  • 通过aop创建的命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了

  • <aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class=“true”/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理

进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了。

  • <aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class=“true”/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理

版权声明:本文为CSDN博主「冢狐」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/issunmingzhi/java/article/details/106051063

Spring 从入门到入土——AOP 就这么简单!| 原力计划

更多精彩推荐

更多精彩推荐

中国最优秀的程序员都有哪些?王兴、张小龙、张一鸣是哪类?| 蒋涛说

☞Service Mesh 如何重定义云原生计算?阿里服务网格技术大揭秘

听说你还没收到端午福利?程序人生来宠你!

秋名山老司机从上车到翻车的悲痛经历,带你深刻了解什么是 Spark on Hive!| 原力计划

MATLAB 被禁点燃导火索,国产软件路在何方?

破碎的互联网下,加密技术正在恢复数据主权!

你点的每个“在看”,我都认真当成了喜欢

原文  http://mp.weixin.qq.com/s?__biz=MjM5MjAwODM4MA==&mid=2650755043&idx=3&sn=35e7a251c838568fe0529889a1509f51
正文到此结束
Loading...