【初学Java学习笔记】AOP与OOP

时间:2024-04-30 23:27:52

AOP(Aspect Oriented Programming) 面向切面编程,是属于Spring框架中的内容。AOP相当于OOP的补充,当我们需要对多个对象引入一个公共行为,比如日志,操作记录等,就需要在每个对象中引用公共行为,这样程序就产生了大量的重复代码,使用AOP可以完美解决这个问题。

AOP实现原理是java动态代理,但是jdk的动态代理必须实现接口,所以spring的aop是用cglib这个库实现的,cglis使用asm这个直接操纵字节码的框架,所以可以做到不使用接口的情况下实现动态代理。

【代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用】

静态代理
首先,我们创建一个Person接口。这个接口就是学生(被代理类),和班长(代理类)的公共接口,他们都有交作业的行为。这样,学生交作业就可以让班长来代理执行。

/**
* 创建person接口
*/
public interface Person {
//交作业
void giveTask();
}
Student类实现Person接口,Student可以具体实施交作业这个行为。

public class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}

public void giveTask() {
System.out.println(name + "交语文作业");
}
}
StudentsProxy类,这个类也实现了Person接口,但是还另外持有一个学生类对象,那么他可以代理学生类对象执行交作业的行为。

/**
* 学生代理类,也实现了Person接口,保存一个学生实体,这样就可以代理学生产生行为
*/
public class StudentsProxy implements Person{
//被代理的学生
Student stu;

public StudentsProxy(Person stu) {
// 只代理学生对象
if(stu.getClass() == Student.class) {
this.stu = (Student)stu;
}
}

//代理交作业,调用被代理学生的交作业的行为
public void giveTask() {
stu.giveTask();
}
}
下面测试一下,看代理模式如何使用:

public class StaticProxyTest {
public static void main(String[] args) {
//被代理的学生林浅,他的作业上交有代理对象monitor完成
Person linqian = new Student("林浅");
//生成代理对象,并将林浅传给代理对象
Person monitor = new StudentsProxy(linqian);
//班长代理交作业
monitor.giveTask();
}
}

这里并没有直接通过林浅(被代理对象)来执行交作业的行为,而是通过班长(代理对象)来代理执行了。这就是代理模式。代理模式就是在访问实际对象时引入一定程度的间接性,这里的间接性就是指不直接调用实际对象的方法,那么我们在代理过程中就可以加上一些其他用途。比如班长在帮林浅交作业的时候想告诉老师最近林浅的进步很大,就可以轻松的通过代理模式办到。在代理类的交作业之前加入方法即可。这个优点就可以运用在spring中的AOP,我们能在一个切点之前执行一些操作,在一个切点之后执行一些操作,这个切点就是一个个方法。这些方法所在类肯定就是被代理了,在代理过程中切入了一些其他操作。

动态代理
动态代理和静态代理的区别是,静态代理的的代理类是我们自己定义好的,在程序运行之前就已经变异完成,但是动态代理的代理类是在程序运行时创建的。相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。比如我们想在每个代理方法之前都加一个处理方法,我们上面的例子中只有一个代理方法,如果还有很多的代理方法,就太麻烦了,我们来看下动态代理是怎么去实现的。

首先还是定义一个Person接口:

/**
* 创建person接口
*/
public interface Person {
//交作业
void giveTask();
}
接下来是创建需要被代理的实际类,也就是学生类:

public class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}

public void giveTask() {
System.out.println(name + "交语文作业");
}
}
创建StuInvocationHandler类,实现InvocationHandler接口,这个类中持有一个被代理对象的实例target。InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。

public class StuInvocationHandler<T> implements InvocationHandler {
//invocationHandler持有的被代理对象
T target;

public StuInvocationHandler(T target) {
this.target = target;
}

/**
* proxy:代表动态代理对象
* method:代表正在执行的方法
* args:代表调用目标方法时传入的实参
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行" +method.getName() + "方法");
Object result = method.invoke(target, args);
return result;
}
}
那么接下来我们就可以具体的创建代理对象了。

/**
* 代理类
*/
public class ProxyTest {
public static void main(String[] args) {

//创建一个实例对象,这个对象是被代理的对象
Person linqian = new Student("林浅");

//创建一个与代理对象相关联的InvocationHandler
InvocationHandler stuHandler = new StuInvocationHandler<Person>(linqian);

//创建一个代理对象stuProxy来代理linqian,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);

//代理执行交作业的方法
stuProxy.giveTask();
}
}
我们执行代理测试类,首先我们创建了一个需要被代理的学生林浅,将林浅传入stuHandler中,我们在创建代理对象stuProxy时,将stuHandler作为参数,那么所有执行代理对象的方法都会被替换成执行invoke方法,也就是说,最后执行的是StuInvocationHandler中的invoke方法。所以在看到下面的运行结果也就理所当然了。

学习总结:AOP的主要优点在于降低了代码之间的耦合度,并且减少了重复代码的书写。从原理来说,不难理解,在使用代理的过程中,通过代理执行被代理对象的方法时,将我们需要加入的公共函数添加到代理类中,从而减少重复代码。

原文链接:https://blog.****.net/qq_41701956/java/article/details/84427891