您的位置:首页 > 编程语言 > Java开发

Spring AOP整理

2015-07-25 10:18 651 查看
AOP的概念很多,初次接触,不好接受,我们一点点来理解。

1. 通知(Advice)

通知定义了想要的功能,在何时使用,以及会干什么事情,自定义通知可以实现Spring中的五种通知,这五种通知下面会有介绍。

2. 连接点(JoinPoint)

连接点是spring允许你使用通知的地方,基本每个方法的前、后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点。

3. 切入点(PointCut)

切入点是在上面说的连接点的基础上来定义的,在一个类里,有15个方法,那么就有几十个连接点,但并不是想在所有方法附近都使用通知(使用叫织入),只想让其中的几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。

4. 切面(Aspect)

切面是通知和切入点的结合。没连接点什么事情,连接点是为了好理解切点,搞出来的。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。

5. 引入(introduction)

引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)。

6. 目标(Target)

即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事),比如人是目标,他是关注我要睡觉这件事,至于睡前和睡后可以不用关心。

7. 代理(proxy)

应用通知的对象。

8. 织入(Weaving)

把切面应用到目标对象来创建新的代理对象的过程。

PS:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理是使用了JDK的动态代理技术,Spring提供了4种实现AOP的方式:

8.1.经典的基于代理的AOP 8.2.@AspectJ注解驱动的切面 8.3.纯POJO切面 8.4.注入式AspectJ切面

9. demo实践

首先看经典的基于代理的AOP,Spring支持五种类型的通知:

前置通知(MethodBeforeAdvice) 后置通知(AfterReturningAdvice) 包围通知(MethodIntercepter)
抛出通知(ThrowAdvice) 引入(IntroductionIntercepter)

这东西怎么玩?大概步骤:

1.创建通知:实现这几个接口,把其中的方法实现了

2.定义切点和通知者:在Spring配置文件中配置这些信息

3.使用ProxyFactoryBean来生成代理

9.1 程序1:

/**
*
*/
package test.spring.aop;

/**
* 具有睡觉能力的生物都可以实现该接口(不光生物,包括关机选项里面的休眠)
*
* @author quyang.ybb
*
*/
public interface Sleepable {

void sleep();
}


/**
*
*/
package test.spring.aop.impl;

import test.spring.aop.Sleepable;

/**
* 这是纯粹的睡觉(业务逻辑),睡觉前后会有一些辅助工作,如脱衣服、吃安眠药等,这些与纯粹的睡觉是不相干的
*
* @author quyang.ybb
*
*/
public class Human implements Sleepable {

@Override
public void sleep() {
System.out.println("好累啊!终于可以睡觉了,谁也别吵我");
}

}


/**
*
*/
package test.spring.aop.help;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

/**
* 里面包含了睡觉的辅助工作,用AOP术语来说它就应该是通知
*
* @author quyang.ybb
*
*/
public class SleepHelper implements MethodBeforeAdvice, AfterReturningAdvice {

public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("睡觉前,我要把衣服脱掉,脱掉!");
}

public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("起床后,我要把衣服穿上,穿上!");
}

}


<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://img.alipay.net/dtd/schema/service http://img.alipay.net/dtd/schema/service/sofa-service.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd" default-autowire="byName">

<bean id="human" class="test.spring.aop.impl.Human"></bean>

<!-- 睡觉帮助类,即通知 -->
<bean id="sleepHelper" class="test.spring.aop.help.SleepHelper"></bean>

<!-- pattern属性指定了正则表达式,它匹配所有的sleep方法 -->
<bean id="sleepPointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*sleep"></property>
</bean>

<!-- 切点仅仅是定义了故事发生的地点,还有故事发生的时间以及最重要的故事的内容,就是通知了,我们需要把通知跟切点结合起来,即切面 -->
<bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="sleepPointCut"></property>
<property name="advice" ref="sleepHelper"></property>
</bean>

<!-- 切入点和通知都配置完成,接下来该调用ProxyFactoryBean产生代理对象了 -->
<bean id="humanProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="human"></property>
<property name="interceptorNames" value="sleepHelperAdvisor"></property>
<property name="proxyInterfaces" value="test.spring.aop.Sleepable"></property>
</bean>

</beans>


package test.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import test.spring.aop.Sleepable;

/**
* 测试程序1
* @author quyang.ybb
*
*/
public class MainTest {

/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/main/context.xml");
Sleepable sleeper = (Sleepable) applicationContext.getBean("humanProxy");
sleeper.sleep();
}
}


运行结果1:

七月 25, 2015 10:11:32 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4586787c: startup date [Sat Jul 25 10:11:32 CST 2015]; root of context hierarchy
七月 25, 2015 10:11:32 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [test/main/context.xml]
七月 25, 2015 10:11:33 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@771a1d97: defining beans [human,sleepHelper,sleepPointCut,sleepHelperAdvisor,humanProxy]; root of factory hierarchy
睡觉前,我要把衣服脱掉,脱掉!
好累啊!终于可以睡觉了,谁也别吵我
起床后,我要把衣服穿上,穿上!


9.2 程序2:其余不变,配置文件变换为context2.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://img.alipay.net/dtd/schema/service http://img.alipay.net/dtd/schema/service/sofa-service.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd" default-autowire="byName">
<!-- context.xml文件中配置切点跟通知过程有点复杂,Spring提供一种自动代理的功能,能让切点和通知自动匹配 -->
<bean id="sleepHelper" class="test.spring.aop.help.SleepHelper"></bean>
<bean id="sleepAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="sleepHelper"></property>
<property name="pattern" value=".*sleep"></property>
</bean>

<bean id="human" class="test.spring.aop.impl.Human"></bean>
<bean id="autoProxyCreator"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>


package test.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import test.spring.aop.Sleepable;

/**
* 测试程序2
* @author quyang.ybb
*
*/
public class MainTest2 {

/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/main/context2.xml");
Sleepable sleeper = (Sleepable) applicationContext.getBean("human");
sleeper.sleep();
}
}


运行结果2:

七月 25, 2015 10:13:54 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7f50388c: startup date [Sat Jul 25 10:13:54 CST 2015]; root of context hierarchy
七月 25, 2015 10:13:54 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [test/main/context2.xml]
七月 25, 2015 10:13:55 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@462eab5b: defining beans [sleepHelper,sleepAdvisor,human,autoProxyCreator]; root of factory hierarchy
睡觉前,我要把衣服脱掉,脱掉!
好累啊!终于可以睡觉了,谁也别吵我
起床后,我要把衣服穿上,穿上!


9.3 程序3:配置文件变换为context3.xml,使用AspectJ提供的注解方式

/**
*
*/
package test.spring.aop.help;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
* @author quyang.ybb
*
*/
// 用@Aspect的注解来标识切面,注意不要把它漏了,否则Spring创建代理的时候会找不到
@Aspect
public class SleepHelper3 {

public SleepHelper3() {

}

// @Pointcut注解指定了切点
@Pointcut("execution(* *.sleep())")
public void sleepPoint() {

}

// @Before指定了运行时的通知,注意的是要在注解中传入切点的名称
@Before("sleepPoint()")
public void beforeSleep() {
System.out.println("睡前我要看一会书");
}

//@AfterReturning指定了运行时的通知,注意的是要在注解中传入切点的名称
@AfterReturning("sleepPoint()")
public void afterSleep() {
System.out.println("睡觉起来我要洗漱,收拾东西");
}
}


<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://img.alipay.net/dtd/schema/service http://img.alipay.net/dtd/schema/service/sofa-service.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd"> <aop:aspectj-autoproxy />
<bean id="sleepHelper3" class="test.spring.aop.help.SleepHelper3"></bean>
<bean id="human" class="test.spring.aop.impl.Human"></bean>
</beans>


package test.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import test.spring.aop.Sleepable;

/**
* 测试程序3
*
* @author quyang.ybb
*
*/
public class MainTest3 {

/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/main/context3.xml");
Sleepable sleeper = (Sleepable) applicationContext.getBean("human");
sleeper.sleep();
}
}


运行结果3:

七月 25, 2015 10:16:28 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7f50388c: startup date [Sat Jul 25 10:16:28 CST 2015]; root of context hierarchy
七月 25, 2015 10:16:28 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [test/main/context3.xml]
七月 25, 2015 10:16:29 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5740aa8a: defining beans [org.springframework.aop.config.internalAutoProxyCreator,sleepHelper3,human]; root of factory hierarchy
睡前我要看一会书
好累啊!终于可以睡觉了,谁也别吵我
睡觉起来我要洗漱,收拾东西


最后我们来看最后一种常用的实现AOP的方式:使用Spring来定义纯粹的POJO切面

前面我们用到了<aop:aspectj-autoproxy/>标签,Spring在aop的命名空间里面还提供了其他的配置元素:

<aop:advisor> 定义一个AOP通知者
<aop:after> 后通知
<aop:after-returning> 返回后通知
<aop:after-throwing> 抛出后通知
<aop:around> 周围通知
<aop:aspect>定义一个切面
<aop:before>前通知
<aop:config>顶级配置元素,类似于<beans>这种东西
<aop:pointcut>定义一个切点

我们用AOP标签来实现睡觉这个过程:代码不变,只是修改配置文件,加入AOP配置即可:

<aop:config>
<aop:aspect ref="sleepHelper">
<aop:before method="beforeSleep" pointcut="execution(* *.sleep(..))"/>
<aop:after method="afterSleep" pointcut="execution(* *.sleep(..))"/>
</aop:aspect>
</aop:config>


完!有需要补充的再继续在此版本上更改,程序附图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: