一、实现Spring IOC功能
* spring 核心
* 容器 IOC AOP
* 1.存放容器的单例池 concurrenthashMap
* 2.存放beanDefinition 存放生成bean的信息
* 3.spring主流程
* 配置包扫描路径-》ApplicationClassLoad 加载类 -》扫描生成beanDefinition放入 -》
* BeanDefinitionMap中 并标识为单例bean或者原型bean 作为生成Bean的信息
* -》根据beanDefinitionMap生成所有 单例bean放入单例池
* -》getBean() 单例bean从单例池中获取 原型bean 根据BeanDefinition生成
* ComponentScan注解解析--》扫描路径--》扫描 -》放入beanDefinitionMap中
1.实现包扫描逻辑 生成BeanDefinition放入 beanDefinitionMap
1.定义包扫描路径
@ComponentScan("com.example.myspring.service")
public class AppConfig {
}
2.定义两个容器 singletonObjects 存放单例bean 和beanDefinitionMap 存放生生成bean的信息
//单例池 存放单例bean
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
//存beanDefinition
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
3.包扫描逻辑
private void scan(Class configClass) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
ComponentScan componentScan = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
//get scan path
String scanPath = componentScan.value();//get scan path
scanPath = scanPath.replace(".", "/");
//扫描 类加载器
// Bootstrap --> jre/lib
// Ext --------> jre/ext/lib
// App ---------> classpath -->
ClassLoader classLoader = MyApplicationContext.class.getClassLoader();//appClassLoader
URL resource = classLoader.getResource(scanPath);
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
String absolutePath = f.getAbsolutePath();
if (absolutePath.endsWith(".class")) {
//get com.example.myspring.service.xxx
String className = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"))
.replace("\", ".");
//classloader loadClass
Class<?> clazz = classLoader.loadClass(className);
if (clazz.isAnnotationPresent(Component.class)) {//判断扫描类是否有 有Component注解 是一个Bean
if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
BeanPostProcessor instance = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
beanPostProcessorList.add(instance);
}
//解析类 生成BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(clazz);
Component component = clazz.getDeclaredAnnotation(Component.class);
String beanName = component.value();
if (clazz.isAnnotationPresent(Scope.class)) {//判断单例bean 原型bean
Scope scope = clazz.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scope.value());
} else {//默认单例bean
beanDefinition.setScope(singleton);
}
beanDefinitionMap.put(beanName, beanDefinition);
}
}
}
}
}
2.扫描完成 遍历beanDefinitionMap 生成bean对象放入单例池
- 遍历beanDefinitionMap 调用createBean() 生成对象放入单例池中
//扫描完成 遍历beanDefinitionMap 单例bean 生成对象放入单例池中
for (String beanName : beanDefinitionMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
Object bean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, bean);
}
2.生成bean逻辑实现 (实现依赖注入)
//create bean
public Object createBean(String beanName, BeanDefinition beanDefinition) throws Exception {
Class clazz = beanDefinition.getClazz();
Object instance = clazz.newInstance();
//依赖注入 逻辑实现
for (Field declaredField : clazz.getDeclaredFields()) {
if (declaredField.isAnnotationPresent(Autowired.class)) {//判断是否存在Autowired注解
//从容器中查找bean 注入到依赖bean中
Object bean = getBean(declaredField.getName());
declaredField.setAccessible(true);
declaredField.set(instance, bean);
}
}
//aware回调:调用bean实现BeanNameAware 接口的方法
if (instance instanceof BeanNameAware) {
((BeanNameAware) instance).setBeanName(beanName);
}
//初始化前 对bean进行加工
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
}
//初始化
if (instance instanceof InitializingBean) {
((InitializingBean) instance).afterPropertiesSet();
}
//初始化后处理 在这进行代理 aop
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
}
return instance;
}
3.getBean()功能实现
getBean()方法逻辑 如果是singleton单例bean直接从单例池获取,如果是原型bean
/**
* getBean 方法 获取一个bean
*
* @return
*/
public Object getBean(String beanName) throws Exception {
Object bean = null;
if (beanDefinitionMap.containsKey(beanName)) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")) {//单例bean 从单例池获取
bean = singletonObjects.get(beanName);
} else {//原型bean
bean = createBean(beanName, beanDefinition);
return bean;
}
} else {//不存在bean
throw new NullPointerException();
}
return bean;
}
二、实现Spring AOP功能
"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块, 并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共 同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未 来的可操作性和可维护性。 使用"横切"技术,AOP 把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流 程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生 在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP 的作用在于分离系统
中的各种关注点,将核心关注点和横切关注点分离开来。
AOP 主要应用场景有:
- Authentication 权限
- Caching 缓存
- Context passing 内容传递
- Error handling 错误处理
- Lazy loading 懒加载
- Debugging 调试
- logging, tracing, profiling and monitoring 记录跟踪 优化 校准
- Performance optimization 性能优化
- Persistence 持久化
- Resource pooling 资源池
- Synchronization 同步
- Transactions 事务
1.定义一个接口
public interface BeanPostProcessor {
//初始化前
Object postProcessBeforeInitialization(Object bean,String beanName);
//初始化后
Object postProcessAfterInitialization(Object bean,String beanName);
}
2.实现接口 在接口逻辑实现代理 找切点执行AOP
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (beanName.equals("userService")) {
System.out.println("userService初始化前处理..");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println(beanName + " 初始化后处理...");
if (beanName.equals("userService")) {
System.out.println("生成代理对象");
Object proxyInstance = Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理逻辑");//找切点 执行aop
//调用代理逻辑
return method.invoke(bean, args);
}
});
return proxyInstance;
}
return bean;
}
}