• Spring之AOP(面向切面编程)_入门Demo


    AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。

            实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态植入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。然而殊途同归,实现AOP的技术特性却是相同的,分别为:

    1 join point(连接点):是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现AOP时,并不需要去定义一个join point。

    2 point cut(切入点):本质上是一个捕获连接点的结构。在AOP中,可以定义一个point cut,来捕获相关方法的调用。

    3 advice(通知):是point cut的执行代码,是执行“方面”的具体逻辑。

    4 aspect(方面):point cut和advice结合起来就是aspect,它类似OOP中定义的一个类,但它代表的更多是对象间横向的关系。

    5 introduce(引入):为对象引入附加的方法或属性,从而达到修改对象结构的目的。有的AOP工具又将其称为mixin。

    上述的技术特性组成了基本的AOP技术,大多数AOP工具均实现了这些技术。它们也可以是研究AOP技术的基本术语。

    举例:假设有在一个应用系统中,有一个共享的数据必须并发同时访问,首先,将这个数据封装在数据对象中,同时,将有多个访问类,专门用于在同一时刻访问这同一个数据对象。

    *Demo实验:

    a.创建两个接口类:TestServiceInter,TestServiceInter2,代码如下:

    // TestServiceInter

    public interface TestServiceInter {

            public void sayHello();

    }

    // TestServiceInter2

    public interface TestServiceInter2 {

            public void sayBye();

    }

    b.创建一个类Test1Service实现以上接口

    public class Test1Service implements TestServiceInter,TestServiceInter2 {

            private String name;

            public void setName(String name) {

                     this.name = name;

            }

            @Override

            public void sayHello() {

                     System.out.println("hi"+name);

            }

            @Override

            public void sayBye() {

                     System.out.println("bye"+name);

            }

    }

    c.创建applicationContext.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:context="http://www.springframework.org/schema/context"

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

               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

                                      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

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

    <!-- 配置被代理的对象 -->

    <bean id="test1Service" class="com.ansibee.aop.Test1Service">

    <property name="name" value="关羽"></property>

    </bean>

    </beans>

    d.创建一个前置通知类MyMethodBeforeAdvice实现MethodBeforeAdvice接口,目的为了在执行sayHello()方法之前执行此段代码。代码如下:

    public class MyMethodBeforeAdvice implements MethodBeforeAdvice{

            /**

             * method:被调用的方法名

             * args:给method传递的参数

             * target:目标对象

             */

            @Override

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

                     // TODO Auto-generated method stub

                     System.out.println("*************");

                     System.out.println("日志记录:"+method.getName());

                    

            }

    }

    创建一个后置通知类MyAfterReturningAdvice实现AfterReturningAdvice接口,目的为了在执行sayBye()方法之后执行此段代码。代码如下:

    public class MyAfterReturningAdvice implements AfterReturningAdvice {

            @Override

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

                     // TODO Auto-generated method stub

                     System.out.println("关闭资源");

            }

    }

    最后创建一个环绕通知类MyMethodInterceptor实现MethodInterceptor接口,环绕通知=前置通知+目标方法执行+后置通知,proceed ()方法就是用于启动目标方法执行的。代码如下:

    public class MyMethodInterceptor implements MethodInterceptor {

            @Override

            public Object invoke(MethodInvocation arg0) throws Throwable {

                     // TODO Auto-generated method stub

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

                     Object obj = arg0.proceed();

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

                     return obj;

            }

    }

    e.完成上述操作后去applicationContext.xml文件中进行相应的配置。代码如下:

    </bean>

    <!-- 配置前置通知 -->

    <bean id="MyMethodBeforeAdvice" class="com.ansibee.aop.MyMethodBeforeAdvice"></bean>

    <!-- 定义前置通知的接入点 -->

    <bean id="MyMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

            <property name="advice" ref="MyMethodBeforeAdvice"></property>

            <property name="mappedNames">

                     <list>

                             <value>sayHello</value>

                     </list>

            </property>

    </bean>

    <!-- 配置后置通知 -->

    <bean id="MyAfterReturningAdvice" class="com.ansibee.aop.MyAfterReturningAdvice"></bean> <!-- 配置环绕通知 -->

    <bean id="MyMethodInterceptor" class="com.ansibee.aop.MyMethodInterceptor"></bean>

    <!-- 配置代理对象 -->

    <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">

    <!-- 配置代理的接口集 -->

    <property name="proxyInterfaces">

    <list>

    <value>com.ansibee.aop.TestServiceInter</value>

    <value>com.ansibee.aop.TestServiceInter2</value>

    </list>

    </property>

    <!-- 把通知织入到代理对象 -->

    <property name="interceptorNames">

    <!-- 相当于把前置通知和代理对象关联,可以把通知看作拦截器-->

    list>

    <!-- 织入前置通知,后置通知,环绕通知-->

    <value>MyMethodBeforeAdviceFilter</value>

    <!-- 使用自定义切入点控制前置使用 -->

    <value>MyAfterReturningAdvice</value>

    <value>MyMethodInterceptor</value>

    </list>

    </property>

    <!-- 通知被代理对象,可以指定-->

    <property name="target" ref="test1Service"></property>

    </bean>

    f.完成一系列配置后,可以进行测试了,测试类代码如下:

    public class TestMain {

            public static void main(String[] args) {

                    

    ApplicationContext ac = new ClassPathXmlApplicationContext("com/ansibee/aop/applicationContext.xml");

                     TestServiceInter ts = (TestServiceInter) ac.getBean("proxyFactoryBean");

                     ts.sayHello();

                     ((TestServiceInter2)ts).sayBye();             

            }

    }

    然后run Java Application,运行结果如图

  • 相关阅读:
    免密码输入ssh连接
    关于调用函数使用栈
    uos中tftp、nfs服务重启方法、路径
    uos安装dogtail首次打开提示可访问性,点击确定按钮如何自动化
    linux查看启动项
    5.gitlab提交时触发jenkins
    Fun blog
    Github Page 加速 | vercel ~~
    98--RocketMQ原生API收发消息
    97--RocketMQ工作原理
  • 原文地址:https://www.cnblogs.com/ansibee/p/7073453.html
Copyright © 2020-2023  润新知