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 >

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

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

<bean >

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

        <property name="mappedNames">

                 <list>

                         <value>sayHello</value>

                 </list>

        </property>

</bean>

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

<bean ></bean> <!-- 配置环绕通知 -->

<bean ></bean>

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

<bean >

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

<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,运行结果如图

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