AOP面向切面编程简单介绍与应用(面向切面编程实例)

  本篇文章为你整理了AOP面向切面编程简单介绍与应用(面向切面编程实例)的详细内容,包含有aop 面向切面 面向切面编程实例 面向切面编程应用场景 面向切面编程一看就明白 AOP面向切面编程简单介绍与应用,希望能帮助你了解 AOP面向切面编程简单介绍与应用。

  什么是AOP

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

  OOP (Object Oriented Programming) 面向对象编程

  AOP (Aspect Oritented Programming) 面向切面编程

  OOP 到AOP 不是替换的关系,而是一种扩展,使用了AOP后,OOP还是会继续使用

  Aop在Spring中的作用

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

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

  切面(ASPECT)︰横切关注点被模块化的特殊对象。即,它是一个类。

  通知(Advice) :切面必须要完成的工作。即,它是类中的一个方法。·

  目标(Target):被通知对象。

  代理(Proxy) ︰向目标对象应用通知之后创建的对象。

  切入点(PointCut) :切面通知执行的“地点""的定义。

  连接点(JointPoint) : 与切入点匹配的执行点。

  AOP 主要就是在不改变原本代码的前提下,新增功能上去不影响原本的功能。

  AOP在Spring中是非常重要的一个功能,可以理解为一个业务就是一条线,当使用一把刀在这条线的指定位置砍下去,添加新的功能到断开处,最后在进行织入,最后连起来成为了一条新的线,新的功能就可以实现。

  使用Spring实现Aop

  添加依赖

  

 !-- https://mvnrepository.com/artifact/org.springframework/spring-aop -- 

 

   dependency

   groupId org.springframework /groupId

   artifactId spring-aop /artifactId

   version 5.3.18 /version

   /dependency

   !-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt --

   dependency

   groupId org.aspectj /groupId

   artifactId aspectjrt /artifactId

   version 1.9.6 /version

   scope runtime /scope

   /dependency

   !-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --

   dependency

   groupId org.springframework /groupId

   artifactId spring-aspects /artifactId

   version 5.3.18 /version

   /dependency

  

 

  修改配置文件

  

 ?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"

   xmlns:context="http://www.springframework.org/schema/context"

   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.xs"

   !--注解扫描 默认开启注解支持--

   context:component-scan base-package="com.bing"/

   proxy-target- 如果是true 就是cglib代理 如果是false就是jdk 默认是false

   aop:aspectj-autoproxy /

   /beans

  

 

  添加一个切面类

  

package com.bing.aspect;

 

  import org.apache.log4j.Logger;

  import org.aspectj.lang.JoinPoint;

  import org.aspectj.lang.ProceedingJoinPoint;

  import org.aspectj.lang.annotation.*;

  import org.springframework.stereotype.Component;

   * @Author IBing

   * @Date 2022/8/26 22:01

   * @Version 1.0

  @Aspect //表示这是一个 切面类

  @Component //将对象放入spring容器

  public class UserAspect {

   //开启日志

   private Logger logger = Logger.getLogger(UserAspect.class);

   * 目标方法执行之前执行

   * @param joinPoint

   @Before("execution(public com.bing.entity.User com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))")

   public void before(JoinPoint joinPoint){

   logger.debug("before");

   logger.debug("拦截的目标对象"+joinPoint.getTarget());

   logger.debug("拦截的方法"+joinPoint.getSignature().getDeclaringTypeName()+joinPoint.getSignature().getName());

   logger.debug("拦截的参数"+joinPoint.getArgs());

   logger.debug("拦截的位置"+joinPoint.getStaticPart());

   logger.debug("拦截的代理对象"+joinPoint.getStaticPart());

   * 无论是否抛出异常都会执行,相当于finally

   * @param joinPoint

   @After("execution(public com.bing.entity.User com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))")

   public void after(JoinPoint joinPoint){

   logger.debug("after");

   logger.debug("拦截的目标对象"+joinPoint.getTarget());

   logger.debug("拦截的方法"+joinPoint.getSignature().getDeclaringTypeName()+joinPoint.getSignature().getName());

   logger.debug("拦截的参数"+joinPoint.getArgs());

   logger.debug("拦截的位置"+joinPoint.getStaticPart());

   logger.debug("拦截的代理对象"+joinPoint.getStaticPart());

   * 相当于try

   * @param joinPoint

   @AfterReturning("execution(public com.bing.entity.User com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))")

   public void afterReturning(JoinPoint joinPoint){

   logger.debug("afterReturning");

   logger.debug("拦截的目标对象"+joinPoint.getTarget());

   logger.debug("拦截的方法"+joinPoint.getSignature().getDeclaringTypeName()+joinPoint.getSignature().getName());

   logger.debug("拦截的参数"+joinPoint.getArgs());

   logger.debug("拦截的位置"+joinPoint.getStaticPart());

   logger.debug("拦截的代理对象"+joinPoint.getStaticPart());

   * 相当于catch

   * @param joinPoint

   * @param e

   @AfterThrowing(value="execution(public com.bing.entity.User com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))",throwing ="e" )

   public void afterThrowing(JoinPoint joinPoint,RuntimeException e){

   logger.debug("afterThrowing");

   logger.debug("拦截的目标对象"+joinPoint.getTarget());

   logger.debug("抛出的异常为",e);

   * 环绕执行

   * @param pjd

   * @return

   * @throws Throwable

   @Around("execution(public com.bing.entity.User com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))")

   public Object around(ProceedingJoinPoint pjd) throws Throwable {

   logger.debug("around之前");

   Object proceed= pjd.proceed();

   logger.debug("around之后");

   return proceed;

  

 

  测试

  

@Test

 

  public void test( ){

   //创建spring的容器并初始化

   ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");

   String[] beanNameForType = classPathXmlApplicationContext.getBeanNamesForType(UserController.class);

   System.out.println(Arrays.toString(beanNameForType));

   UserController bean = (UserController) classPathXmlApplicationContext.getBean("userController");

   bean.login("aa","123"); //这是 UserController 里写好的login方法

   classPathXmlApplicationContext.close();

  

 

  输出结果
 

  因为没有异常,所以 **afterThrowing **方法没有执行

  上面每个方法的切入点都一样,代码重复,我们可以定义切入点,

  

//定义切入点

 

  @Pointcut("execution(public com.bing.entity.User com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))")

  private void pointCut(){}

  

 

  然后在切面类的方法上使用切入点方法就行,这样就减少了代码重复

  

/**

 

   * 目标方法执行之前执行

   * @param joinPoint

  @Before("pointCut()")

  public void before(JoinPoint joinPoint){

   logger.debug("before");

   logger.debug("拦截的目标对象"+joinPoint.getTarget());

   logger.debug("拦截的方法"+joinPoint.getSignature().getDeclaringTypeName()+joinPoint.getSignature().getName());

   logger.debug("拦截的参数"+joinPoint.getArgs());

   logger.debug("拦截的位置"+joinPoint.getStaticPart());

   logger.debug("拦截的代理对象"+joinPoint.getStaticPart());

  

 

  下面是一些切入点语法

  

execution() 切入点

 

  直接精准到一个方法上面去

  execution( public com.bing.entity.User com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))

  任意权限修饰符

  execution( com.bing.entity.User com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))

  无返回类型

  execution( void com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))

  有返回类型

  execution( !void com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))

  任意返回类型

  execution( * com.bing.service.impl.UserServiceImpl.login(java.lang.String,java.lang.String))

  execution( * com.bing.service.impl.UserServiceImpl.login(..))

  类中的任意方法

  execution( * com.bing.service.impl.UserServiceImpl.*(..))

  类中以指定内容开头的方法

  execution( * com.bing.service.impl.UserServiceImpl.select*(..))

  包中的任意类的任意方法不包含子包下面的类

  execution( * com.bing.service.impl.*.*(..))

  包中及其下的任意类的任意方法

  execution( * com.bing.service..*.*(..))

  

 

  

pointcut 切入点 定义切入的连接点, 一般对应的就是表达式

 

  aspect 切面 拥有具体功能的一个类

  advice 通知 切面的具体实现 对应的就是切面类中的方法

  joinpoint 连接点 程序运行中可以插入切面的地方 在spring中只能是方法 比如login方法

  target 目标对象 切入的对象 这个对象包含了业务代码的具体实现 比如:UserServiceImpl类的对象

  proxy 代理对象 目标对象应用了通知以后创建的一个新的对象,这个对象中包含了原本的业务实现和扩展实现

  weaving 织入 将通知应用到目标对象后创建代理对象的过程

  

 

  XML实现AOP

  首先在配置文件中进行AOP相应的配置

  

 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/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"

   !--开启注解支持,,让项目支持spring的注解--

   !-- context:annotation-config /context:annotation-config --

   !--注解扫描 默认开启注解支持--

   context:component-scan base-package="com.bing"

   !--设置需要扫描的注解--

   !-- context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/ --

   !--设置不扫描的注解--

   !-- context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/ --

   /context:component-scan

   打开动态代理

   proxy-target- 就是cglib代理 ,为false则会使用jdk代理实现,默认为false

   aop:aspectj-autoproxy proxy-target- /

   !-- 下面这些就是AOP的XML实现方式--

   bean id="userAspect" /

   aop:config

   aop:aspect ref="userAspect"

   !-- 定义切面--

   aop:pointcut id="pc" expression="execution(* com.bing.service.impl.UserServiceImpl.*(..))"/

   aop:before method="before" pointcut-ref="pc"/

   aop:after-returning method="afterReturning" pointcut-ref="pc"/

   aop:after-throwing method="afterThrowing" pointcut-ref="pc" throwing="e"/

   aop:after method="after" pointcut-ref="pc"/

   !-- 如果不想使用已经定义的切入点 pc,也可以使用pointcut="execution()"来自己定义,这里演示就使用相同的切入点--

   aop:around method="around" pointcut="execution(* com.bing.service.impl.UserServiceImpl.*(..))"/

   /aop:aspect

   /aop:config

   /beans

  

 

  切面类

  

package com.bing.aspect;

 

  import org.apache.log4j.Logger;

  import org.aspectj.lang.JoinPoint;

  import org.aspectj.lang.ProceedingJoinPoint;

  import org.aspectj.lang.annotation.*;

  import org.springframework.stereotype.Component;

   * @Author IBing

   * @Date 2022/8/26 22:01

   * @Version 1.0

  //@Aspect //表示这是一个 切面类

  @Component //将对象放入spring容器

  public class UserAspect {

   private Logger logger = Logger.getLogger(UserAspect.class);

   * 目标方法执行之前执行

   * @param joinPoint

   public void before(JoinPoint joinPoint){

   logger.debug("before");

   logger.debug("拦截的目标对象"+joinPoint.getTarget());

   logger.debug("拦截的方法"+joinPoint.getSignature().getDeclaringTypeName()+joinPoint.getSignature().getName());

   logger.debug("拦截的参数"+joinPoint.getArgs());

   logger.debug("拦截的位置"+joinPoint.getStaticPart());

   logger.debug("拦截的代理对象"+joinPoint.getStaticPart());

   * 无论是否抛出异常都会执行,相当于finally

   * @param joinPoint

   public void after(JoinPoint joinPoint){

   logger.debug("after");

   logger.debug("拦截的目标对象"+joinPoint.getTarget());

   logger.debug("拦截的方法"+joinPoint.getSignature().getDeclaringTypeName()+joinPoint.getSignature().getName());

   logger.debug("拦截的参数"+joinPoint.getArgs());

   logger.debug("拦截的位置"+joinPoint.getStaticPart());

   logger.debug("拦截的代理对象"+joinPoint.getStaticPart());

   * 相当于try

   * @param joinPoint

   public void afterReturning(JoinPoint joinPoint){

   logger.debug("afterReturning");

   logger.debug("拦截的目标对象"+joinPoint.getTarget());

   logger.debug("拦截的方法"+joinPoint.getSignature().getDeclaringTypeName()+joinPoint.getSignature().getName());

   logger.debug("拦截的参数"+joinPoint.getArgs());

   logger.debug("拦截的位置"+joinPoint.getStaticPart());

   logger.debug("拦截的代理对象"+joinPoint.getStaticPart());

   * 相当于catch

   * @param joinPoint

   * @param e

   public void afterThrowing(JoinPoint joinPoint,RuntimeException e){

   logger.debug("afterThrowing");

   logger.debug("拦截的目标对象"+joinPoint.getTarget());

   logger.debug("抛出的异常为",e);

   * 环绕执行

   * @param pjd

   * @return

   * @throws Throwable

   public Object around(ProceedingJoinPoint pjd) throws Throwable {

   logger.debug("around之前");

   Object proceed= pjd.proceed();

   logger.debug("around之后");

   return proceed;

  

 

  运行结果

  以上就是AOP面向切面编程简单介绍与应用(面向切面编程实例)的详细内容,想要了解更多 AOP面向切面编程简单介绍与应用的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: