什么是AOP
AOP就是面向切面编程,可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
AOP的主要意图
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
可能这样说大家不是理解的很明白,那么请看下面的代码。
假设有一个业务组件Component,其中有3个业务方法:
public class Component implements Icomponent{
public void business1()
{
System.out.println("业务1");
}
public void business2()
{
System.out.println("业务2");
}
public void business3()
{
System.out.println("业务3");
}
}
现在有一个需求,在不改动业务逻辑代码的情况下,在每个业务方法执行前都必须执行一个用户验证,如下:
public void validateUser(){
System.out.println(“验证用户”);
}
在这个情况下我们就用到了AOP。
AOP有如两种实现方式
1.静态代理
2.动态代理
AOP的静态代理
特点
①程序中调用执行的是代理对象,构造代理对象时给它一个被代理对象;
②代理对象代替真正的对象来执行其方法,并在执行过程中添加额外的职责;
③代理对象的一个接口只服务于一种类型的对象,如果代理的方法很多,势必要为每种方法进行代理。
1.将Component 的业务逻辑拿出来创建一个接口,
public interface Icomponent {
public void business1();
public void business2();
public void business3();
}
2.实现代理对象,这个实现了业务逻辑接口
public class ComponentProxy implements Icomponent{
private Component component;
//初始化component
public ComponentProxy(Component component)
{
this.component=component;
}
public void validateUser()
{
System.out.println("用户验证");
}
public void business1()
{
//加入验证用户
this.validateUser();
//调用原有的业务逻辑
component.business1();
}
public void business2()
{
this.validateUser();
component.business2();
}
public void business3()
{
this.validateUser();
component.business3();
}
}
3.测试函数
public class AopExample {
public static void main(String[] args) {
Icomponent proxy=new ComponentProxy(new Component());
proxy.business1();
proxy.business2();
//用接口对象调用方法
proxy.business3();
}
}
AOP的动态代理
特点:使用动态代理可以使得一个处理者(Handler)服务于各个对象
通过实现InvocationHandler接口实现动态代理
public class ValidateHandler implements InvocationHandler{
public Object delegate;
//绑定代理对象
public Object bind(Object delegate)
{
this.delegate=delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
}
//代理对象每次操作时都会调用invoke方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
try
{
System.out.println("方法开始"+method);
this.validateUser();
result=method.invoke(delegate, args);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public void validateUser()
{
System.out.println("验证用户");
}
}
测试函数
public class AopExample {
public static void main(String[] args) {
ValidateHandler validatehandler=new ValidateHandler();
Icomponent proxy=(Icomponent)validatehandler.bind(new Component());
proxy.business1();
proxy.business2();
proxy.business3();
}
}
小结
使用代理对象将日志等与业务逻辑无关的动作或任务提取出来,设计成为一个服务对象称为Aspect,将上述这些与业务逻辑无关的动作在AOP中称之为Cross-cutting concern
SpringAOP
Aspect
散落于各个业务逻辑之中的Cross-cutting concerns收集起来,设计成为独立可重用的对象,称为Aspect。
Advice
Aspect当中对Cross-cutting concerns的具体实现称为Advice
Jointpoint
Advice在应用程序执行时加入业务流程的点或时机(只支持方法的Jointpoint)
Pointcut
Pointcut定义了感兴趣的Jointpoint,当调用的方法符合Pointcut表达式时,将Advice织入到应用程序中。
Target
被代理的对象(一个Advice被应用的对象)
Introduction
可以为某个已编写或编译完的类,在执行时期动态加入一些方法
Weave
Advice被应用到Target上的过程,不同时间点(Compile、Classload、Runtime)
由于Weave到Target的时机不同,Spring提供了几种不同的Advices(Before Advice、After Advice 、Around Advice、Throw Advice)
例如:beforeadvice可通过实现MethodBeforeAdvice接口实现
public class ValidateBeforeMethod implements MethodBeforeAdvice{
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
// 执行用户验证,并打印执行方法
this.validate();
System.out.println(arg0);
}
public void validate()
{
System.out.println("验证用户");
}
}
//在spring的配置文件中配置bean
<bean id="validatebeforeadvice" class="com.cst.spring.lab3.ValidateBeforeMethod"/>
<bean id="component" class="com.cst.spring.lab3.Component"/>
<bean id="componentproxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.cst.spring.lab3.Icomponent"/>
<property name="target" ref="component"/>
<property name="interceptorNames">
<list>
<value>validatebeforeadvice</value>
</list>
</property>
</bean>
//测试类
public class AopExample {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
Icomponent icom=(Icomponent)context.getBean("componentproxy");
icom.business1();
}
}
便可在执行icom.business1();之前调用用户验证
其余advice也是一样
spring2.0AOP的命名空间
在Spring2.0中,可以使用标签来定义After Returning Advice,不用实现AfterReturningAdvice接口,此文不在描述,想学习者自行找资料学习。(需要架包 aspectjweaver.jar、asm-.jar、asm-commons-.jar
)
本文到此结束,有错误请指出,谢谢。