AOP原理与实现

1.AOP简介

AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向方面(切面)编程。
它将分布在各个类中具有相同功能的代码片段整合到一起,由单独的功能模块完成,不仅减少了代码的重复量,降低了耦合,也提高了代码的可维护性。
AOP的作用就是在可以顺序执行的程序中,插入某些特殊的逻辑来实现一些特殊的功能 ,例如日志、事务、安全等都可以很方便的使用AOP来实现。
不要认为AOP会取代OOP,它只是OOP的补充。但就像当年的OOP一样,它很可能引发一场软件产业的革命。

AOP把软件系统分成两部分:核心关注点和横切关注点。
所谓核心关注点,是业务处理的主要流程,也就是说这个解决方案要做的事。
所谓横切关注点,是与核心关注点无关的部分,常常发生在核心关注点的多处,而各处基本相似,如日志 、权限等。

AOP的核心思想是将应用程序中的商业逻辑和对其进行支持的通用服务进行分离。
目前,宣称能够支持AOP的项目已达近百种,Java语言的实现也有20多种,其中最为完善的是AspectJ。

采用AOP之前                                 采用AOP之后
                                                                        

2.AOP术语
切面(Aspect):从对象中抽取出来的横切性功能模块。类似与OOP中的一个类。由通知和切入点两部分组成。
通知(Adivice):切面的具体实现,例如具体的日志操作代码,一般是是切面中的某个方法。
连接点(Joinpoint):目标对象中插入通知的地方。即advice的应用位置。spring中只支持是方法
切入点(Pointcut):切面的一部分,对应一个表达式,定义了advice应该被插入到什么样的Joinpoint点上,即 advice的应用范围
目标对象(Target Object):被通知的对象。
代理(AOP Proxy):由AOP框架创建的目标对象的代理对象。是被插入了advice的Target Object 。
织入(Weaving):将通知与目标对象结合在一起,生成新的对象的过程。新的对象就是AOP Proxy 。Spring是在运行时完成织入工作的。
引入(Introduction):为已经存在的类添加新方法和属性,从而达到修改对象内部结构的目的。
3.AOP实现技术
Spring使用两种机制实现AOP技术:
一是使用java的动态代理,即java.lang.reflect.Proxy类创建代理( 注解方式和配置方式两种实现手段)。
二是使用CGLIB库自动生成目标对象的子类,同时织入通知。
动态代理要求目标对象必须要实现接口(只有这样才能创建代理),而CGLIB则没有这种限制。
目前AOP还没有完全的统一标准,因此实现出来的AOP框架也是多种多样的,为此人们成立了一个AOP联盟,用于统一这种混乱局面。

一 : 注解方式实现 AOP
关键步骤
切面操作
加入aspect注解
编写ponintcut方法并添加注解
编写advice方法并添加注解
修改spring配置文件:
启用aspectJ对anotation的支持
配置切面类和目标对象类

如下例:
切 面LogAspect.java
@Aspect 
public class LogAspect  {

@Pointcut ("execution(* save*(..))||execution(* delete*(..))")
public void allSaveMethod(){}

@Before("allSaveMethod()")
public void log()
{
System.out.println("------------write log into logfile--------------");
}
}


修改spring配置文件:
<aop:aspectj-autoproxy />

<bean id="userManager" class="cn.bsw.spring.annotation.UserManagerImpl“/>

<bean id="logAspect" class="cn.bsw.spring.annotation.LogAspect"/>

Pointcut表达式
任意公共方法的执行:
execution(public * *(..))
任何一个以“set”开始的方法的执行:
execution(* set*(..))
AccountService 接口的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
定义在service包里的任意方法的执行:
execution(* com.xyz.service.*.*(..))
定义在service包或者子包里的任意方法的执行:
execution(* com.xyz.service..*.*(..))

Advice类型:
前置通知(Before advice)
一个切面里使用 @Before 注解声明前置通知:
后置通知(After (finally) advice)
不论一个方法是如何结束的,在它结束后(finally)后通知(After (finally) advice)都会运行。 使用 @After 注解来声明。  
返回后通知(After returning advice)
返回后通知通常在一个匹配的方法返回时执行。使用 @AfterReturning 注解来声明:
抛出后通知(After throwing advice)
抛出后通知在一个方法抛出异常后执行。使用 @AfterThrowing 注解来声明:
环绕通知(Around Advice)
环绕通知环绕通知在一个方法执行之前和之后执行,使用 @Around 注解来声明。


二: 配置文件实现 AOP

关键步骤
编写aspect类,只需advice即可
修改spring配置文件:
配置<aop:config>
配置<aop:aspect> 指定切面类
配置<aop:pointcut>指定哪些对象的哪些方法订阅切面
配置advice如:<aop:before><aop:after>等。

如下例:
切面LogAspect.java
public class LogAspect  {
public void log(JoinPoint  joinPoint)
{   Object args[]= joinPoint.getArgs();
for( int i=0;i<args.length;i++)
System.out.println(args[i]);
System.out.println(joinPoint.getSignature().getName());
System.out.println(joinPoint.getSignature().getDeclaringTypeName());
System.out.println("------------write log into logfile--------------");
}
}


可为Advice添加一个JoinPoint参数,这个值会由spring自动传入,从中可以取得连接点的参数值、方法名等信息。

修改spring配置文件
<bean id="userManagerImpl" class="cn.bsw.aop.xmlconf.UserManagerImpl" />
<bean id="logAspect" class="cn.bsw.aop.xmlconf.LogAspect" />

<aop:config>
<aop:aspect id="log"  ref="logAspect">
<aop:pointcut id="allSaveMethod"  expression="execution(* save*(..))||execution(* delete*(..))"/>
    <aop:after  method="log" pointcut-ref="allSaveMethod"/>
</aop:aspect>
</aop:config>

注意和annotation方式对比,会发现配置内容一致,只是位置和格式不同而已

CGLIB实现AOP
spring对AOP的支持
如果目标对象实现了接口,默认情况下采用JDK动态代理实现AOP
如果目标对象实现了接口,可以强制使用CGLIB实现AOP
如果目标对象没有实现接口,自动采用CGLIB库实现AOP

如何强制使用CGLIB实现AOP?
在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

JDK动态代理和CGLIB字节码生成的区别?
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值