AOP技术(3)


1、通过xml配置文件实现AOP

​ 流程:

  1. 将所有的切片操作放到一个类中。
  2. 在xml配置文件中,通过扫描器、手动配置两种方式,得到被代理类对象和切片类对象。
  3. 通过<aop:config>标签,配置切面,切入点以及增强哪些方法。
  4. main函数中只需解析xml文件,得到返回的代理类对象,然后用接口或代理类去引用它。

切片类:

//配置扫描器别名
@Component("xmlAspect")
public class XMLAspectDemo &#123;
    // 前置通知
    public void mybefore(JoinPoint joinPoint) &#123;
        System.out.print("调用方法之前起作用...");
        System.out.print("代理对象的对象:"+joinPoint.getTarget() );
        System.out.println(",被织入增强处理的目标方法为:"
                            +joinPoint.getSignature().getName());
        System.out.print("before 方法结束........");
    &#125;
    // 后置通知
    public Object myAfterReturn(JoinPoint joinPoint) &#123;
        System.out.print("调用方法之后...," );
        System.out.println("被织入增强处理的目标方法为:"
                          + joinPoint.getSignature().getName());
        return null;
    &#125;
    /**
     * 环绕通知
     * ProceedingJoinPoint 是JoinPoint子接口,表示可以执行目标方法
     * 1.必须是Object类型的返回值
     * 2.必须接收一个参数,类型为ProceedingJoinPoint
     * 3.必须throws Throwable
     */
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) 
             throws Throwable &#123;
        // 开始
        System.out.println("环绕开始:执行目标方法之前,模拟开启事务...");
        // 执行当前目标方法
        Object obj = proceedingJoinPoint.proceed();
        // 结束
        System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
        return obj;
    &#125;
    // 异常通知
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) &#123;
        System.out.println("异常通知:" + "出错了" + e.getMessage());
    &#125;
    // 最终通知
    public void myAfter() &#123;
        System.out.println("最终通知:模拟方法结束后的释放资源...");
    &#125;
&#125;

JoinPoint是插入点。类似的还有PointCut,advice,advicer。

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

           <!-- 使用扫描器创建对象 -->
         <context:component-scan base-package="com.hugeyurt.aspect"/>
     <!-- 手动创建对象 -->
    <!--  <bean id="myAspect" class="com.hugeyurt.aspect.XMLAspectDemo" /> 
     <bean id="serviceDemo2" class = "com.hugeyurt.aspect.ServiceDemo2" /> -->

    <!-- aop编程 -->
    <aop:config>
        <!-- 配置切面 -->
        <aop:aspect ref="xmlAspect">
          <!-- 3.1 配置切入点,通知最后增强哪些方法 -->
          <aop:pointcut expression="execution(* com.hugeyurt.aspect.*.*(..))"
                                                      id="myPointCut" />
            <!-- 第一个*:所有该全限定名 。   第二个*:所有类。    第三个*:所有方法。        括号:所有形参 -->
            <!-- 3.2 关联通知Advice和切入点pointCut -->
            <!-- 3.2.1 前置通知 -->
            <aop:before method="mybefore" pointcut-ref="myPointCut" />
            <!-- 3.2.2 后置通知,在方法返回之后执行,就可以获得返回值
             returning属性:用于设置后置通知的第二个参数的名称,类型是Object -->
            <!-- <aop:after-returning method="myAfterReturning"
                pointcut-ref="myPointCut" returning="point" /> -->
            <!-- 3.2.3 环绕通知 -->
            <!-- <aop:around method="myAround" pointcut-ref="myPointCut" /> -->
            <!-- 3.2.4 抛出通知:用于处理程序发生异常-->
            <!-- * 注意:如果程序没有异常,将不会执行增强 -->
            <!-- * throwing属性:用于设置通知第二个参数的名称,类型Throwable -->
            <!-- <aop:after-throwing method="myAfterThrowing"
                pointcut-ref="myPointCut" throwing="e" /> -->
            <!-- 3.2.5 最终通知:无论程序发生任何事情,都将执行 -->
            <!-- <aop:after method="myAfter" pointcut-ref="myPointCut" /> -->
        </aop:aspect>
    </aop:config>
</beans>

main函数:

public static void main(String[] args) &#123;
        // TODO Auto-generated method stub

          ApplicationContext appContext = new ClassPathXmlApplicationContext(
                    new String[] &#123; "applicationContext.xml" &#125;);
        // 1 从spring容器获得内容
        IAopDemo demo = (IAopDemo) appContext.getBean("serviceDemoOne");
        //ServiceDemo2 demo = (ServiceDemo2) appContext.getBean("serviceDemo2");
        // 2 执行方法
         demo.printA();
        //demo.printName();
    &#125;

​ 这种方式比起上一个版本,将所有的切片方式放到一个类中,并且可以对被代理类的任意方法进行切片处理,在XML配置文件中也可以通过扫描器的方式获取所有对象,更加灵活。

​ 但是XML配置文件过于冗杂,繁琐。下个版本将会解决这个问题。

2、简化xml,实现AOP

​ 流程:

  1. 通过@Component注解获得切面类
  2. 通过@Aspect注解获得具体切面信息
  3. 通过@Before(“自己定义的方法”)等注解,决定使用哪个切片
  4. main正常调用

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: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-4.3.xsd
  http://www.springframework.org/schema/aop 
  http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-4.3.xsd">
      <!-- 指定需要扫描的包,使注解生效 -->
      <context:component-scan base-package="com.hugeyurt.aspect.annotation" />
      <!-- 启动基于注解的声明式AspectJ支持 -->
      <aop:aspectj-autoproxy />

</beans>

切面类:

/**
 * 切面类,在此类中编写通知
 */
@Component
@Aspect
public class AspectAnnotation &#123;
    // 定义切入点表达式
    @Pointcut("execution(* com.hugeyurt.aspect.annotation.*.*(..))")
    // 使用一个返回值为void、方法体为空的方法来命名切入点
    private void myPointCut()&#123;&#125;
    // 前置通知

    @Before("myPointCut()")
    public void myBeforeafdasf(JoinPoint joinPoint) &#123;
        System.out.print("前置通知 :模拟执行权限检查...,");
        System.out.print("目标类是:"+joinPoint.getTarget() );
        System.out.println(",被织入增强处理的目标方法为:"
                       +joinPoint.getSignature().getName());
      String method=joinPoint.getTarget().getClass().getName()+"-"+joinPoint.getSignature().getName();
      System.out.println(method);
      Object[] args=joinPoint.getArgs();
       for (Object object : args) 
       &#123;
           System.out.println(object.getClass().getName());
           System.out.println(object.toString());

       &#125;
    &#125;
    // 后置通知
    //@AfterReturning(value="myPointCut()")
    public void myAfterReturning(JoinPoint joinPoint) &#123;
        System.out.print("后置通知:模拟记录日志...," );
        System.out.println("被值入增强处理的目标方法为:"
                      + joinPoint.getSignature().getName());

    &#125;
    // 环绕通知    
    //@Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) 
            throws Throwable &#123;
        // 开始
        System.out.println("环绕开始:执行目标方法之前,模拟开启事务...");
        // 执行当前目标方法
        Object obj = proceedingJoinPoint.proceed();
        // 结束
        System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
        return obj;
    &#125;
    // 异常通知
    //@AfterThrowing(value="myPointCut()",throwing="e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) &#123;
        System.out.println("异常通知:" + "出错了" + e.getMessage());
    &#125;
    // 最终通知
    //@After("myPointCut()")
    public void myAfter() &#123;
        System.out.println("最终通知:模拟方法结束后的释放资源...");
    &#125;
&#125;

main函数:

    public static void main(String[] args) &#123;
        // TODO Auto-generated method stub
          ApplicationContext appContext = new ClassPathXmlApplicationContext(
                    new String[] &#123; "beansAnnotation.xml" &#125;);
        // 1 从spring容器获得内容
          ServiceDemo demo = (ServiceDemo) appContext.getBean("serviceDemo");
          IHello demo2 = (IHello) appContext.getBean("serviceDemo2");

        // 2 执行方法
          demo.printName("kitty",89);
          demo2.sayHello("hello");
    &#125;

​ 对比上个版本,这个版本更加简便。

​ 通过三种注解,获得了切面类的所有信息,并通过spring容器实现了切片功能。通过正则表达式可以在任意方法处实现切片操作。


文章作者: kilig
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kilig !
 上一篇
基于AOP实现分页 基于AOP实现分页
1、实现思路​ 之前做的分页只是session级别的,在同一个session中才可以取分页信息。 ​ 基于AOP技术实现的分页功能是application级别,所有访问web项目的请求,只要满足条件,就可以从se
下一篇 
AOP技术(2) AOP技术(2)
1. 通过自己的spring内核实现AOP配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans> <bean name="before" class="com.h
2020-08-01
  目录