AOP编程的概念
AOP的概念
AOP(Aspect Oriented Programing)面向切面编程 = spring动态代理开发
以切尔缅为基本单位进行程序开发,通过切面间的彼此调用,相互协同,完成程序的构建
切面 = 切入点+ 额外功能
OOP(Object Oriented Programing)面向对象编程
以对象为基本单位进行程序开发,通过对象间的彼此协同,相互协调,完成程序的构建
POP(Producer Oriented Programing)面向过程(方法,函数)编程
以过程为基本单位的程序开发,通过彼此间协同,相互调用,完成程序的构建
AOP的概念:本质上就是 Spring动态代理开发,有益于原始类的维护
注意:AOP编程不可能取代OOP,OOP编程有意补充。
切面名词解释
切面= 切入点 + 额外功能
几何学:面 = 点 + 相同的功能
AOP底层实现原理
核心问题
1、AOP如何创建字节代理类(动态字节码技术)
2、Spring是如何通过原始对象的ID值获取的代理对象那?
通过原始对象的id值,获得的是代理对象
动态代理的创建
动态代理的创建的创建方式有两种,一种是基于jdk的动态代理;另外一种是基于cglib的动态代理。
JDK的动态代理
由上图可以知道:
代理创建需要三要素:1 原始对象 2 额外功能 3 代理对象实现相同的接口。
Proxy.newProxyInstance(ClassLoader ,interfaces, invocationHandler)需要三个参数:
1、ClassLoader:完成代理类的创建,可以去借一个
通过类加载器把对应类的字节码加载到JVM中
通过类加载器创建class对象,进而创建这个类的对象
如何获得类加载器?
每个类的.class文件 自动分配与之对应的ClassLoder
在动态代理创建的过程中,需要ClassLoader创建代理类的Class对象,可是动态代理类没有对应的.class文件,JVM也不会为其分配ClassLoader,但是又需要怎么办?
借用一个ClossLoader
2、interfaces:原始对象所实现的接口
创建代理类的class对象,进而完成代理类的创建
3、invocationHandler:额外需要增加的功能
用于书写额外功能 额外功能:原始方法执行前后 抛出异常
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
- Object proxy 忽略掉,表示的是代理对象
- Method method 额外功能所增加给的那个原始方法
- Object[] args 原始方法的参数
- method.invoke(object, args) 原方法运行
最终完成所有的数据的组合:
//注意:类加载器是借用来的 可以随表找一个借用
public class JDKProxy {
public static void main(String[] args) {
// 在JDK8.0之前 内部变量访问外部变量需要加final
final UserService userService = new UserServiceImpl();
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----login-------");
//原方法运行
Object obj = method.invoke(userService, args);
return obj;
}
};
UserService service = (UserService) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
service.login("bearjun","hello");
service.register(new User());
}
}
CGlib动态代理
CGlib创建动态代理的原理:通过父子继承关系创建代理对象,原始类作为父类,代理类作为 > 子类,这样既可以保证2者方法⼀致,同时在代理类中可以提供新的实现(额外功能+原始方法)。
有上图可以知道:
# 对于一些没有实现接口的方法
public class UserServiceImpl(){
login();
register();
}
# 代理类 继承你要代理的类
public clss Proxy extends UserServiceImpl(){
login(){
额外功能
super.login();
}
}
最终cglib的动态代理实现:
public class TestCglib {
public static void main(final String[] args) {
//创建原始对象
final UserService userService = new UserService();
/*
通过cglib方式创建动态代理对象
Proxy.newProxyInstance(ClassLoader ,interfaces, invocationHandler)
*/
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(TestCglib.class.getClassLoader());
enhancer.setSuperclass(userService.getClass());
MethodInterceptor interceptor = new MethodInterceptor() {
//等同于 InvocationHandler -- invoke
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("hello world");
Object invoke = method.invoke(userService, args);
return invoke;
}
};
enhancer.setCallback(interceptor);
UserService userServiceProxy = (UserService) enhancer.create();
userServiceProxy.login();
userServiceProxy.register();
}
}
cglib同样也需要做这些:
- enhancer.setClassLoader(); 类加载器,可以借
- enhancer.setSuperclass(); 原始方法继承父类的class
- enhancer.setCallback(); --> MethodInterceptor(cglib包下) 增强方法
- enhancer.create() 原方法运行
刚才在网上看到说:Cglib invoke以及invokeSuper的一点区别: 简而言之,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 MyMethodInterceptor的 interceptor方法,如果是个拦截器链条,就会重新在走一次拦截器链;
相关链接:https://www.cnblogs.com/lvbinbin2yujie/p/10284316.html
总结:
- JDK动态代理 Proxy.newProxyInstance() 通过接口创建代理类
- Cglib动态代理 Enhancer 通过继承父类创建的代理类
Spring工厂加工代理对象
刚才说的第2个问题:Spring是如何通过原始对象的ID值获取的代理对象那?
通过原始对象的id值,获得的是代理对象。那通过id为什么获取的是代理对象呢?
模拟编码:
public class ProxyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("--- new log ---");
Object ret = method.invoke(bean, args);
return ret;
}
};
return Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), handler);
}
}
<bean id="userService" class="com.yusael.factory.UserServiceImpl"/>
<!--1. 实现 BeanPostProcessor 进行加工-->
<!--2. 配置文件中对 BeanPostProcessor 进行配置-->
<bean id="proxyBeanPostProcessor" class="com.bearjun.factory.ProxyBeanPostProcessor"/>
原来spring在初始化的时候,利用了动态代理的技术,在初始化的时候,把原始的bean换成了代理对象。
评论区