关于java切面编程了解:
目前java切面编程在java开发及其他软件开发领域的应用十分广泛,在java1.5加入注解功能后更是如虎添翼,目前认知值停留在模糊的概念阶段:java切面编程通过jdk和cglib两种动态代理模式,可以在类和方法还有注解上切入,因此其所能实现的功能就十分强悍了。
切面编程主要优点:在不修改源码的基础上更加容易的扩展功能,将功能代码从业务逻辑中分离出来,便以不至于在业务代码中需要大量的使用功能代码和设计模式,如以前的Android SDK开发包。总结起来就是解耦,易扩展,高性能,高效率,高复用率。
切面编程主要功能:日志记录,性能统计,安全控制,事务处理,异常处理,等等。
关于切面编程的概念:
面向切面编程(Aspect Oriented Programming),以下简称AOP。
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(以上概念在百度百科上非常详细的介绍)
关于AOP的底层实现原理:
总所周知,AOP的底层由jdk动态代理和cglib动态代理实现,是否还有其他模式,我就不得而知了,但基本上就是这两个模式,所以首先我们得明白什么是代理模式(23种基本设计模式中的一种)思想,以及动态代理的实现方式。其概念的东西不在本篇幅中展开详细的说明,因此要深入了解AOP就必须要掌握代理模式和动态代理实现的两种模式。因此这部分基础十分重要,必要掌握。
java动态代理的两种实现方式:
AOP的拦截功能由java中的动态代理来实现,就是在目标类的基础上增加切面逻辑,生成增强的目标类。(该切面逻辑可以在目标类函数执行之前,或者目标类执行之后,或者在目标类函数抛出异常的时候执行。不同的切入时机对应不同的Interceptor的种类。如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)
jdk动态代理:
jdk动态代理是jdk原生就支持的一种代理方式,它的实现原理,就是通过让target类和代理类实现同一接口,代理类持有target对象,来达到方法拦截的作用,这样通过接口的方式就有两个弊端,一是必须保证target类有接口,第二个是如果想要对target类的方法进行拦截,那么就要保证这些方法在接口中声明,实现上略微有点限制。
? 示例代码:略(在ecli-test本地工程中)
1.定义一个简单的接口
public interface IUser {
void addUser();
}
2.实现该接口
import com.common.service.IUser;
public class UserImpl implements IUser {
public void addUser() {
// 这里是代码逻辑,我们省略,只打印一句话,做为演示
System.out.print("------------add user success----------");
}
}
3.定义一个代理类实现InvacationHandler
public class MyInvocation implements InvocationHandler {
private Object target;
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 加入该对象执行之前的代码逻辑,这里我们只打印一句话,复杂的逻辑也是一样加在这里
System.out.print("对象执行之前的代码逻辑");
// 返回代理对象
Object resultObject = method.invoke(target, args);
// 加入该对象执行之后的代码逻辑,这里我们只打印一句话,复杂的逻辑也是一样加在这里
System.out.print("对象执行之后的代码逻辑");
return resultObject;
}
public MyInvocation(Object target) {
this.target = target;
}
}
4.测试调用
public static void main(String[] args) {
// 得到代理对象
MyInvocation myInvocationHandler = new MyInvocation(new UserImpl());
IUser proxy = (IUser) Proxy.newProxyInstance(MyInvocation.class.getClassLoader(),
new Class[] { IUser.class }, myInvocationHandler);
// 调用方法
proxy.addUser();
}
主要实现步骤:新建接口和接口实现类
代理类实现InvocationHandler接口重写invoke方法,在该类中传入target类的接口,通过Proxy.newProxyInstance()方法返回代理对象,在invoke方法中做增强。
cglib动态代理:
CGLIB(Code Genertation Library)是一个开源项目。意为强大的高性能代码生成包,底层通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类,可在运行期扩展java类与实现java接口。
? 示例代码:略(在ecli-test本地工程中)
1.同样使用上面的UserImpl类。
2.定义一个代理类实现MethodInerceptor.
public class ProxySaler implements MethodInterceptor {
public static Object getProxy(Class classs){
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(classs);
// 设置enhancer的回调对象
enhancer.setCallback(new ProxySaler());
// 创建代理对象
Object proxy= enhancer.create();
return proxy;
}
/**
* o:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
Object object = methodProxy.invokeSuper(o, objects);
System.out.println("======插入后者通知======");
return object;
}
}
3.测试调用
public class CGLIBProxy {
@Test
public void test(){
UserImpl proxy = (UserImpl) ProxySaler.getProxy(UserImpl.class);
proxy.addUser();
}
}
主要步骤:代理类实现MethodInteceptor接口,重写interceptor()方法,并在该方法切入做增强。
通过Enhancer对象根据target类的字节码生成相应的代理对象和回调对象
关于CGLIB的底层实现原理以及其它强大的应用,可以去看源码。
关于AOP的一些专业术语:(这些概念非常的晦涩,请务必先了解代理模式,以及动态代理)
Joinpoint(连接点):类里面可以被增强的方法,这些方法称为连接点。
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint(方法)进行拦截的定义。
Advice(通知/增强):所谓通知就是指拦截到Joinpoint之后我们所有做的事情,通知分为前置通知,后置通知, 异常通知,最终通知,环绕通知。
Aspect(切面):是切入点和通知的结合,即对连接点的拦截定义和增强的逻辑或通知。
Introduction(引介):引介是一种特殊的通知,在不修该类代码的前提下,Introduction可以在运行期为类动态地 添加一些方法和属性。
Target(目标对象):代理的目标对象(即需要增强的类)
Weaving(织入):是把增强应用到目标的过程,把advice应用到target的过程。
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
概念总结:以上提取了一些重要的面向切面编程的理解的一些前置概念和个人见解,总的来说就是利用代理设计模式实现了动态代理的技术,然后在通过动态代理这些技术来实现面向切面编程,从而解决了一些复杂问题的目的。
spring aop :另起篇幅
springboot aop 注解权限验证实现:https://segmentfault.com/a/1190000012845239
Aspectj 切面包:另起篇幅