Spring IOC/DI和动态代理AOP底层原理(底层代码实现)
(1)Spring IOC/DI原理
思想:反转控制,依赖注入,将对象创建和对象属性赋值的权利,从当前的代码中转移spring工厂中
原理: 工厂设计模式+反射+配置文件
public class BeanFactory{
public Object getObject(String name){
//根据name获得对应的全类名(properties配置文件)
String className = ...;
Class clazz = Class.forName(className);
return clazz.newInstance();
}
}
应用好处(使用): 解耦和,将对象创建和属性赋值的耦合解开
比如开发中Service,Controller,DAO对象,连接池,事务管理器,都可以从spring工厂中获得,实现了解耦和效果
(2)SpringAOP底层实现原理
AOP思想:面向切面编程,在不修改目标代码的情况的情况下,动态为其增加额外功能。
SpringAOP技术本质:使用了动态代理的设计模式,为目标类的代码,生成一个代理类,产生代理对象,替换目标对象接受调用
静态代理
① 编码:
与目标对象相同的接口、有额外功能、拥有目标对象,调用目标对象的方法
② 代码:
public class UserServiceProxy implements UserService{
private UserService userService = new UserServiceImpl();
public void regist(){
System.out.println("前置增强");
userService.regist(); //调用目标对象的方法
System.out.println("前置增强");
}
}
③ 解释:
作用:实现了事务,日志,权限,性能代码解耦和
缺点:所有静态代理类,都是程序员人工编写,为每个目标类,都要书写一个代理类,代码冗余
Jdk动态代理[基于接口的]
动态代理:代理类是通过代码自动生成的。
特点:
要求目标类必须有接口
Object proxy = Proxy.newProxyInstance(ClassLoader,目标类的接口,增强功能类); //直接生成代理类,生成对象
重要参数:ClassLoader: 动态字节码技术,动态生成一个类信息的byte[],借助于classloader,将byte[]转化为Class对象
目标类接口:UserService
public class Proxy0 implements UserService{
public void regist(){
//核心代码
}
}
增强功能类:书写额外功能,类似Spring的MethodInterceptor
代理类产生过程
类加载
JDK动态代理的代码实现:
目标对象:UserServiceImpl
额外功能增强的类:InvocationHandler
生成代理类:Object proxy = Proxy.newProxyInstance(类加载器,目标类的接口,增强功能);
public static void main(String[] args) {
//① 准备目标对象
final UserService us = new UserServiceImpl();
//② 准备额外功能(接口实现)
InvocationHandler handler = new InvocationHandler() {
/** proxy: 产生当前代理对象
* method: 目标对象的方法
* args: 目标对象的方法实际传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置额外增强代码
//目标对象的目标方法调用
Object o = method.invoke(us, args); //相当于mi.proceed();
//后置额外增强代码
return o;
}
};
//③ 生成代理类,产生代理对象
Object proxy = Proxy.newProxyInstance(us.getClass().getClassLoader(), us.getClass().getInterfaces(), handler);
System.out.println(proxy.getClass().getSimpleName());
UserService usproxy = (UserService) proxy;
usproxy.regist(); //调用方法
}
基于继承的静态代理:
代理类核心要素:与目标类有相同的方法[继承目标类,覆盖父类方法]、额外功能代码、调用目标对象方法
静态代理第二种实现:
目标类:
public class YellowLaodaye{
public void saleHouse() {
System.out.println("签合同,收钱,交易过程。");
}
}
代理类:
public class $Proxy1 extends YelloLaodaye{
@Override
public void saleHouse(){
//增添的额外功能
super.方法();
}
}
Cglib的动态代理:
cglib动态代理技术: 生成基于继承的代理类,及其对象
编码步骤:
额外功能:InvocationHander(cglib包下)
目标对象:目标类 target = new 目标类();
组装生成代理类:
增强器: EnHancer
① 绑定父类:父类.class
② 组合额外功能:handler
③ 生成代理类的对象:eh.create();
示例代码:
//① 目标对象
final YellowLaodaye yld = new YellowLaodaye();
//② 增强功能
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//前置增强。
System.out.println("1. 发广告!");
System.out.println("2. 看房子!");
//调用目标对象的目标方法。
Object obj = method.invoke(yld, args);
return obj;
}
};
//③ 组装生成代理类的对象
Enhancer eh = new Enhancer();
eh.setSuperclass(YellowLaodaye.class); //绑定父类
eh.setCallback(handler); //绑定额外功能对象
Object proxy = eh.create(); //生成代理类对象
YellowLaodaye proxylaodaye = (YellowLaodaye) proxy;
proxylaodaye.saleHouse();
总结Springaop原理(重要):
1) 本质:(李代桃僵)为目标类,使用动态字节码技术(jdk动态代理,cglib动态代理)动态生成代理类,反射创建代理类的对象,替换原有的目标对象。
注意:
① 如果目标类有接口,spring默认会使用jdk动态代理,
② 如果目标类没有接口,但是能够被继承(没有被final修饰),spring会自动切换使用cglib动态代理技术,
③ 如果目标类,没有接口且被final修饰,无法完成代理类生成。
2) Jdk动态代理:基于接口的方式生成代理类、要求目标类必须有接口
3) Cglib动态代理:基于继承的方式生成代理类、要求目标类必须能够被继承【不能用final修饰】
4) 补充:动态代理性能
Jdk版本每次更新,都会大幅度提升Jdk动态代理性能,jdk1.8以后,Jdk动态代理性能完胜cglib