1.为什么会有AOP?
2.AOP的思想。
3.AOP术语
Aspect(切面):
将散落于各个业务逻辑之中的Cross-cutting concerns收集起来,设计成各个独立可重用的对象,这些对象称为Aspect
例:动态代理中的LogHandler就是一个Aspect
Advice(增强):
在特定的连接点上执行的动作,执行的这个动作就相当于对原始对象的功能做了增强。
Aspect对Cross-cutting concerns(横切关注点)的具体实现称为Advice。
Advice中包括了Cross-cutting concerns的行为或所要提供的服务
例:在动态代理的示例中代理类的invoke()就是Advice的具体实例
Joinpoint(连接点):
Advice在应用程序执行时加入业务流程的点或时机称为Joinpoint,具体来说就是Advice在应用程序中被执行的时机
Spring只支持方法的Joinpoint,执行时机可能是某个方法被执行之前或之后
Pointcut(切入点):切入点就是一系列连接点的集合。
Pointcut定义了感兴趣的Joinpoint,当调用的方法符合Pointcut表示式时,将Advice织入应用程序上提供服务
在Spring中,您可以在定义文件或Annotation中编写Pointcut,说明哪些Advice要应用至方法的前后
Target(目标对象):真正执行业务逻辑的对象
一个Advice被应用的对象或目标对象,也就是被代理的类
例:在动态代理的示例中HelloSpeaker就是LogHandler中Advice的Target
Weave(织入):将切面整合到程序的执行流程中
Advice被应用至对象之上的过程称为织入,在AOP中织入的方式有几个时间点:
编译时期
类加载时期
执行时期
4.编写第一个AOP程序:
1)首先写代码 package com.gxa.bj.aspect
/**
* @author chenqing
*这是一个切面的类,这个切面类为游戏提供装备
*/
public class Equip {
public void before(){//增强方法前的调用
System.out.println("选择了一件装备");
}
/**
* @param joinpoint
* @return
* @throws Throwable
* 正在增强的方法
*/
public Object around(ProceedingJoinPoint joinpoint) throws Throwable{
Object object = joinpoint.proceed();
System.out.println("正在增强的方法");
System.out.println("杀伤力提高两倍,防御能力提高两倍");
return object;
}
public void after(){ // 切面织入的方法使用完毕
System.out.println("装备使用完毕");
}
}
2)编写业务处理代码。针对接口的编程package com.gxa.bj.service
先编写一个接口Play:
public interface Play {
public void playGame();
}
编写用户:
public class RouseRole implements Play{
@Override
public void playGame() {
// TODO Auto-generated method stub
System.out.println("Rouse去打游戏");
}
}
public class JeckRole implements Play{
@Override
public void playGame() {
// TODO Auto-generated method stub
System.out.println("Jeck去打游戏");
}
}
3)编写切面和业务的bean对象,在配置前引入aop的命名空间:
xmlns:aop="http://www.springframework.org/schema/aop"<span style="white-space:pre"> </span>
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!-- 配置切面类 -->
<bean id="equipbean" class="com.gxa.bj.aspect.Equip"/>
<!-- 配置目标对象类 -->
<bean id="Jeck" class="com.gxa.bj.service.JeckRole"/>
<bean id="Rouse" class="com.gxa.bj.service.RouseRole"/>
4)配置AOP增强
<aop:config>
<aop:aspect id="equipaspect" ref="equipbean">
<!-- 配置切入点,切入点要满足表达式 -->
<aop:pointcut expression="execution(* com.gxa.bj.service.*.*(..))" id="pointcut"/>
<!-- 要植入增强方法的匹配 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
5)在程序中调用(注意,动态代理针对的是接口编程)
ApplicationContext appcontext = new ClassPathXmlApplicationContext("applicationContext.xml");
Play Jeckplay=(Play) appcontext.getBean("Jeck");
Play Rouseplay=(Play) appcontext.getBean("Rouse");
Jeckplay.playGame();
Rouseplay.playGame();
关于切面表达式的说明:
1.方法签名定义切入点举例:
1)execution(public * *(..))
匹配所有目标类的public方法,其中第一个*表示返回类型,第二个*表示方法名,其中..表示任意类型和个数的参数
2)execution(* find*(..)):匹配所有目标类以find为前缀的方法
2.通过类定义切入点
execution(* com.gxa.bj.service.ZhangSanService.*(..))匹配该业务类下所有的方法。
3.通过类包定义切入点
execution(* com.gxa.bj.service.*(..):匹配该包下所有的的类和方法
execution(* com.gxa.bj.service..*(..):匹配该包下,子孙包下所有类的方法。注意:如果..出现在类名中,后面必须跟上*
4.通过方法形参定义切入点。
execution(* meet(String,int)):匹配所有包的meet方法,且参数为String 类和int类型的