AOP模式的理解?
一、介绍
首先我们知道OOP是面向对象编程,主要是实现了顶层向下发送请求,底层向上提供服务的过程! 而所谓面向对象开发是指将实现某个业务的过程分解成由多个对象的行为和属性配合而完成的过程! 那么我们可以知道这个过程肯定是分散而有序的,可以是由一个个由一个或多个对象协作完成的部分组成!
那么AOP在里面充当什么角色呢? spring的AOP主要实现了为单独一个或多个部分提供一些特殊的功能。我们将OOP理解为纵向开发的话,AOP则可以理解为横向开发。为组成纵向的某些流程提供一些切入的服务。
通俗地讲,以面向对象的理念来理解。组成OOP的每个部分又可以看成一个个的对象。AOP使用的场景就是当这些对象有某种权限或者某种需求,但是这些对象没有时间或者自己不乐意去完成的时候。将自己的权限信息交给AOP,AOP作为代理者,代为完成!
二、代理模式
AOP的理念是二十四设计模式中的代理模式,因此学会写AOP框架前,我们需要先理解下代理模式! 第一步部分说到AOP是获取了对象的身份信息,有了权限后才代为完成! 代理模式中的体现更为完善,如下:
代理模式分为静态代理与动态代理?
1.静态代理?
接口类:
package aop.aop;
/**
* @Auther: CYQ
* @Date: 2019/2/17 21:52
* @Description: 学习的接口
*/
public interface IStudy {
/**
* 学习第一步_读书
* @param bookName
*/
public void readBooks(String bookName);
}
接口实现类:
package aop.aop;
/**
* @Auther: CYQ
* @Date: 2019/2/17 21:53
* @Description: 学习的实现类
*/
public class StudyEnglish implements IStudy {
/**
* 读书
* @param bookName
*/
@Override
public void readBooks(String bookName) {
System.out.println("读:"+bookName+"这本英语书");
}
}
代为完成的对象:
package aop.aop;
import sun.nio.cs.ext.ISCII91;
/**
* @Auther: CYQ
* @Date: 2019/2/17 21:56
* @Description:
*/
public class ProxyStudy implements IStudy {
/**
* 代理获取Study的信息
*/
private IStudy iStudy;//此处为什么用了接口而不是StudyEnglish ,是使用了多态,方便同类型的方法都可以
public ProxyStudy(IStudy iStudy){
this.iStudy=iStudy;
}
@Override
public void readBooks(String bookName) {
System.out.println("-----------专家定制学习内容-----------");
iStudy.readBooks("根据专家定制的内容,学习:"+bookName);
System.out.println("-----------专家评估学习效果-------");
}
}
如何调用与实现呢?
package aop.aop;
/**
* @Auther: CYQ
* @Date: 2019/2/17 22:01
* @Description:
*/
public class StudyGroup {
/**
* 调用
* @param args
*/
public static void main(String[] args){
ProxyStudy proxyStudy=new ProxyStudy(new StudyEnglish());
proxyStudy.readBooks("《黑骏马》");
}
}
可以非常直观地发现,静态代理模式下,我们可以对方法readBooks()进行重新处理,执行对象也由原来的StduyEnglish转换为 代理学习的对象ProxyStudy。集合Spring中AOP的理解,这就是一个简化版本的AOP?
那么Spring的AOP与我们的简易版本AOP有什么区别呢?我们发现spring的AOP可以代理各种对象,而我们的简易版本只能代理我们定义的IStudy类型!那么我们需要进一步优化,引入动态代理模式!
2.动态代理?
JAVA中存在着反射机制,可以让人根据方法名。然后在jvm内存区中查找整个具体内容,从而获取该方法的使用权限。AOP的本质也是获取到对象的权限后,利用其代为工作。因此为了方便开发,JDK1.3版本后,Java官方提供了一个InvactionHandler。利用此API接口可以实现动态代理。。。。。。
package aop.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Auther: CYQ
* @Date: 2019/2/18 14:39
* @Description: 动态代理类
*/
public class StudyCourse implements InvocationHandler {
/**
* 被代理的对象信息
*/
private Object target;
/**
* 获取代理对象并内部,进行回调
* @param object
* @return
*/
public Object getProxyClass(Object object){
this.target=object;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
* 回调对象内容
* @param proxy 代理者,如果引入需要类似targer定义好全局变量
* @param method 被代理类的方法
* @param args 被代理者传入的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* 此处可以根据需要进行AOP事务的切入
*/
//调用目标方法并获取返回结果
Object res=method.invoke(this.target,args);
/**
* 此处可以根据需要进行AOP事务的切入
*/
return res;
}
}
以上为动态代理模式下如何通过反射机制获取代理对象。那么当我们需要为代理对象引入某一个早已经写好的公公模块的时候,应该怎么处理。我们可以将公共模块交给执行代理的执行者。再通过执行者去执行。如下:
package aop.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Auther: CYQ
* @Date: 2019/2/18 14:39
* @Description: 动态代理类
*/
public class StudyCourseLogger implements InvocationHandler {
/**
* 被代理的对象信息
*/
private Object target;
/**
* 执行代理的人
*/
private Object proxy;
/**
* 获取代理对象并内部,进行回调
* @param object
* @return
*/
public Object getProxyClass(Object object,Object logger){
this.target=object;
this.proxy=logger;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
* 回调对象内容
* @param proxy 代理者,代为完成的操作者
* @param method 被代理类的方法
* @param args 被代理者传入的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* AOP事务切入举例
* @getDeclaredMehod() 方法区中class文件中的所有方法,并筛选出合适的一个
*/
Class clazz =proxy.getClass();
//反射得到操作者的Start方法
Method method_proxy = clazz.getDeclaredMethod("执行代理的内部方法名", new Class[]{Method.class});
method_proxy.invoke(proxy, new Object[]{proxy.getClass()});
//调用目标方法并获取返回结果
Object res=method.invoke(this.target,args);
/**
* 此处可以根据需要进行AOP事务的切入
*/
return res;
}
}
调用方式如下:
package aop.aop;
import aop.Hello;
/**
* @Auther: CYQ
* @Date: 2019/2/17 22:01
* @Description:
*/
public class StudyGroup {
/* *//**
* 调用
* @param args
*//*
public static void main(String[] args){
ProxyStudy proxyStudy=new ProxyStudy(new StudyEnglish());
proxyStudy.readBooks("《黑骏马》");
}*/
/**
* 调用
* @param args
*/
public static void main(String[] args){
/**
* 通过反射机制动态获取代理对象信息
*/
IStudy strudyEnglish2=(IStudy) new StudyCourse().getProxyClass(new StudyEnglish());
strudyEnglish2.readBooks("《黑骏马》");
/**
* 通过反射机制动态获取代理对象信息,同时hello为代理者,将代理内容给切入到代理者的方法中
*/
IStudy strudyEnglish3=(IStudy) new StudyCourseLogger().getProxyClass(new StudyEnglish(),new Hello());
strudyEnglish3.readBooks("《黑骏马》");
}
}
由此,我们可以知道AOP的实现如上所述,而在spring中,我们还可以看到各种AOP的引用,如声明式注解的出现。比如日志打印,比如声明式事务。其本质也是AOP的实现。这便是spring的AOP