什么是AOP?
AOP(Aspect-Oriented-Programing)面向切面编程,是一种编程理念。该理念能够是那些为多个业务所共有,却与业务逻辑没有关系的模块抽取出来,形成一个切面。这样可以减少重复代码,并使业务逻辑保持简单,是代码易于维护和扩展。
Spring中是怎么实现AOP的?
Spring是通过JDK动态代理和CGLib(Code Generation Library)字节码生成技术,来实现AOP的,默认在对象存在接口时,使用JDK动态代理,否则使用CGLib。
先看下静态代理
public class AopTest {
public static void main(String[] args) {
Student student=new Student("lily");
student.speak();
}
}
public interface IStudent {
void speak();
}
public class Student implements IStudent{
String name;
public Student(String name) {
this.name = name;
}
public void speak(){
System.out.println("my name is "+name);
}
}
执行main 方法得到
my name is lily
如果我们想在student对象speak之前都加一个句,“hello !”,怎么实现呢?
可以使用代理模式,即新写一个类继承Istudent,然后传入student。
public class StudentProxy implements Humen{
Student student;
public StudentProxy(Student student) {
this.student=student;
}
@Override
public void speak() {
System.out.println("hello !");
student.speak();
}
}
public class AopTest {
public static void main(String[] args) {
Student student=new Student("lily");
StudentProxy studentProxy=new StudentProxy(student);
studentProxy.speak();
}
}
执行得到:
hello !
my name is lily
静态代理成功。
如果有多个方法都要代理呢,那么我们就要在静态代理中写对应个数的代理方法。这很显然不够灵活。
那么就引出了动态代理。
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("hello !");
Object result=method.invoke(object,args);
return result;
}
}
建立一个某功能的动态代理类,可以用来校验,或者记录日志,即我们常用的AOP功能。
继承自InvocationHandler,并将想要增强的功能写在invoke重写方法里。
使用
public class AopTest {
public static void main(String[] args) {
Student student=new Student("lily");
//使用动态代理类代理对象
DynamicProxy dynamicProxy=new DynamicProxy(student);
//使用该代理类
IStudent student1=(IStudent) Proxy.newProxyInstance(IStudent.class.getClassLoader(),new Class[]{IStudent.class},dynamicProxy);
student1.speak();
}
}
结果:
hello !
my name is lily
成功代理该对象。
添加一个ask 方法
public interface IStudent {
void speak();
void ask();
}
public class Student implements IStudent{
String name;
public Student(String name) {
this.name = name;
}
public void speak(){
System.out.println("my name is "+name);
}
public void ask(){
System.out.println("who is "+name);
}
}
调用:
public class AopTest {
public static void main(String[] args) {
Student student=new Student("lily");
//使用动态代理类代理对象
DynamicProxy dynamicProxy=new DynamicProxy(student);
//使用该代理类
IStudent student1=(IStudent) Proxy.newProxyInstance(IStudent.class.getClassLoader(),new Class[]{IStudent.class},dynamicProxy);
student1.speak();
student.ask();
}
}
结果:
hello !
my name is lily
hello !
who is lily
ask方法也被代理了。
使用动态代理的流程为:
1.写动态代理类,继承自InvocationHandler 并重写invoke方法,在该方法中进行增强。
2.通过代理类传入希望被代理对象,生成动态代理对象
3.将动态代理对象传入Proxy静态方法newProxyInstance,得到已被代理的对象
4.通过已被代理对象执行方法
关于动态代理和CGLib应用的具体代码,见:这篇文章