- 什么是AOP
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。
- AOP的基本概念
(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
- AOP 的使用实例
假设我们有这样一个类:
package com.javatpoint;
public class Operation{
public void msg(){System.out.println("msg() method invoked");}
public int m(){System.out.println("m() method invoked");return 2;}
public int k(){System.out.println("k() method invoked");return 3;}
public void display(){System.out.println("display() is invoked");}
public void validate(int age)throws Exception{
if(age<18){
throw new ArithmeticException("Not valid age");
}
else{
System.out.println("Thanks for vote");
}
}
}
那么我们想要基于这个类的一些方法来做一些定制的操作,例如,打印log等.
我们便需要定义一个Aspect类:
package com.javatpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class TrackOperation{
@Pointcut("execution(* Operation.*(..))")
public void k(){}//pointcut name
@Pointcut("execution(* Operation.k*(..))")
public void ok(){}//pointcut name
@AfterReturning(
pointcut = "execution(* Operation.*(..))",
returning= "result")
public void myadvice(JoinPoint jp,Object result)//it is advice (after returning advice)
{
System.out.println("after returning, additional concern");
System.out.println("Method Signature: " + jp.getSignature());
System.out.println("Result in advice: "+result);
System.out.println("end of after returning advice...");
}
@Before("ok()")//applying pointcut on before advice
//@After("k()")//applying pointcut on after advice
public void myadvice(JoinPoint jp)//it is advice
{
System.out.println("before additional concern");
//System.out.println("Method Signature: " + jp.getSignature());
}
@After("k()")//applying pointcut on after advice
public void afteradvice(JoinPoint jp)//it is advice
{
System.out.println("after additional concern");
//System.out.println("Method Signature: " + jp.getSignature());
}
@Around("k()")
public Object myadvice(ProceedingJoinPoint pjp) throws Throwable
{
System.out.println("Additional Concern Before calling actual method");
Object obj=pjp.proceed();
System.out.println("Additional Concern After calling actual method");
return obj;
}
@AfterThrowing(
pointcut = "execution(* Operation.*(..))",
throwing= "error")
public void myadvice(JoinPoint jp,Throwable error)//it is advice
{
System.out.println("1additional concern");
System.out.println("1Method Signature: " + jp.getSignature());
System.out.println("1Exception is: "+error);
System.out.println("1end of after throwing advice...");
}
}
可以看到, 我们需要定义一些point cut,这些pointcut 指定了我们要使用哪些方法.
例如:
@Pointcut(“execution(* Operation.(…))") 表示所有的方法
@Pointcut("execution( Operation.k*(…))”) 表示以k开头的方法
同时,在拦截的时候,有几个注解,例如:
@Before(“ok()”)
@After(“k()”)
@Around(“k()”)
@AfterThrowing(
pointcut = “execution(* Operation.(…))",
throwing= “error”)
@AfterReturning(
pointcut = "execution( Operation.*(…))”,
returning= “result”)
等.
那么测试类如下:
package com.javatpoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test{
public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Operation e = (Operation) context.getBean("opBean");
System.out.println("calling msg...");
e.msg();
System.out.println("calling m...");
e.m();
System.out.println("calling k...");
e.k();
System.out.println("calling validate...");
try{
e.validate(19);
}catch(Exception ex){System.out.println(ex);}
System.out.println("calling validate again...");
try{
e.validate(11);
}catch(Exception ex){System.out.println(ex);}
}
}
大家可以测试打印下结果.
综上,AOP技术利用一种称为“横切”的技术,解剖封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,这样就能减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。
后续写AOP底层原理篇,敬请期待.