Spring AOP整理

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>

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值