文章目录
- 阶段2—封装bean定义信息到Map
- 1.代码框架图
- 2.代码实现
- 1.文件目录
- 2.新增注解Scope存储单例或多例信息Scope.java
- 3.修改MonsterService.java指定多例注解
- 4.新增bean定义对象存储bean定义信息BeanDefinition.java
- 5.修改pom.xml增加依赖
- 6.修改容器实现bean定义信息扫描SunSpringApplicationContext.java
- 7.结果展示
- 3.该阶段完成的任务
- 阶段3—初始化bean单例池&实现依赖注入
- 1.初始化bean单例池
- 1.代码框架图
- 2.代码实现
- 1.修改SunSpringApplicationContext.java增加两个方法
- 2.修改SunSpringApplicationContext.java在构造方法初始化单例池
- 3.启动类AppMain.java
- 4.结果
- 3.该阶段完成的任务
- 2.实现依赖注入
- 1.代码实现
- 1.增加注解Autowired用来表示自动装配
- 2.修改MonsterDao.java
- 3.修改MonsterService.java
- 4.修改SunSpringApplicationContext.java的createBean,添加依赖注入逻辑
- 5.启动类AppMain.java
- 6.结果
- 3.总结IOC
- 1.单例bean的创建和依赖注入
- 2.多例bean的特殊处理
阶段2—封装bean定义信息到Map
1.代码框架图
2.代码实现
1.文件目录
2.新增注解Scope存储单例或多例信息Scope.java
package com.sun.spring.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {String value() default "";
}
3.修改MonsterService.java指定多例注解
package com.sun.spring.component;import com.sun.spring.annotation.Component;
import com.sun.spring.annotation.Scope;@Scope(value = "prototype")
@Component(value = "monsterService")
public class MonsterService {
}
4.新增bean定义对象存储bean定义信息BeanDefinition.java
package com.sun.spring.ioc;
public class BeanDefinition {private String scope; private Class clazz; public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}public Class getClazz() {return clazz;}public void setClazz(Class clazz) {this.clazz = clazz;}@Overridepublic String toString() {return "BeanDefinition{" +"scope='" + scope + '\'' +", clazz=" + clazz +'}';}
}
5.修改pom.xml增加依赖
<dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency>
6.修改容器实现bean定义信息扫描SunSpringApplicationContext.java
package com.sun.spring.ioc;import com.sun.spring.annotation.Component;
import com.sun.spring.annotation.ComponentScan;
import com.sun.spring.annotation.Scope;
import org.apache.commons.lang.StringUtils;import java.io.File;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SunSpringApplicationContext {private Class configClass;private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();public SunSpringApplicationContext(Class configClass) throws ClassNotFoundException {this.beanDefinitionScan(configClass);}public void beanDefinitionScan(Class configClass) throws ClassNotFoundException {this.configClass = configClass;ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);String path = componentScan.value();System.out.println("要扫描的包=" + path);ClassLoader classLoader = SunSpringApplicationContext.class.getClassLoader();path = path.replace(".", "/");URL resource = classLoader.getResource(path);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")) {String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.indexOf("."));String fullPath = path.replace("/", ".") + "." + className;Class<?> aClass = classLoader.loadClass(fullPath);if (aClass.isAnnotationPresent(Component.class)) {System.out.println("这是一个Spring bean=" + aClass);BeanDefinition beanDefinition = new BeanDefinition();Scope scopeAnnotation = aClass.getDeclaredAnnotation(Scope.class);String scope = scopeAnnotation == null || scopeAnnotation.value().equals("") ?"singleton" : scopeAnnotation.value();beanDefinition.setScope(scope);beanDefinition.setClazz(aClass);Component componentAnnotation = aClass.getDeclaredAnnotation(Component.class);String beanName = componentAnnotation.value().equals("") ?StringUtils.uncapitalize(className) : componentAnnotation.value();beanDefinitionMap.put(beanName, beanDefinition);} else {System.out.println("这不是一个Spring bean=" + aClass);}}}System.out.println("遍历输出beanDefinitionMap");for (Map.Entry<String, BeanDefinition> beanDefinitionMap : beanDefinitionMap.entrySet()) {System.out.println(beanDefinitionMap.getKey() + " " + beanDefinitionMap.getValue());}}}public Object getBean(String name) {return null;}}
7.结果展示
3.该阶段完成的任务
- 新增注解Scope来存储单例/多例信息
- 新增bean定义对象,存储bean定义信息Scope和Class对象
- 扫描所有组件的信息,将bean定义信息以beanName - bean定义对象的形式存储到Map中
阶段3—初始化bean单例池&实现依赖注入
1.初始化bean单例池
1.代码框架图
2.代码实现
1.修改SunSpringApplicationContext.java增加两个方法
private Object createBean(BeanDefinition beanDefinition){Class clazz = beanDefinition.getClazz();try {Object instance = clazz.getDeclaredConstructor().newInstance();return instance;} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}}public Object getBean(String name) {if (beanDefinitionMap.containsKey(name)) {BeanDefinition beanDefinition = beanDefinitionMap.get(name);if ("singleton".equals(beanDefinition.getScope())) {return singletonObjects.get(name);} else {return createBean(beanDefinition);}} else {throw new NullPointerException("没有该bean");}}
2.修改SunSpringApplicationContext.java在构造方法初始化单例池
public SunSpringApplicationContext(Class configClass) throws ClassNotFoundException {this.beanDefinitionScan(configClass);Enumeration<String> keys = beanDefinitionMap.keys();while (keys.hasMoreElements()) {String beanName = keys.nextElement();BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if (beanDefinition.getScope().equals("singleton")) {Object bean = createBean(beanDefinition);singletonObjects.put(beanName, bean);}}System.out.println("singletonObjects: " + singletonObjects);}
3.启动类AppMain.java
package com.sun.spring;import com.sun.spring.ioc.SunSpringApplicationContext;
import com.sun.spring.ioc.SunSpringConfig;
public class AppMain {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {SunSpringApplicationContext ioc = new SunSpringApplicationContext(SunSpringConfig.class);Object bean01 = ioc.getBean("monsterDao111"); Object bean02 = ioc.getBean("monsterDao111"); System.out.println("单例对象1:" + bean01);System.out.println("单例对象2:" +bean02);Object bean1 = ioc.getBean("monsterService");Object bean2 = ioc.getBean("monsterService");System.out.println("多例对象1:" + bean1);System.out.println("多例对象1:" + bean2);}
}
4.结果
3.该阶段完成的任务
- 新增createBean的方法,根据bean定义对象创建bean对象
- 新增初始化单例池,在封装完bean定义信息之后,扫描bean定义信息,如果是单例对象则创建bean对象放到单例池中
- 新增getBean方法,如果是单例的对象,则从单例池中查找,否则直接创建对象
2.实现依赖注入
1.代码实现
1.增加注解Autowired用来表示自动装配
package com.sun.spring.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {}
2.修改MonsterDao.java
package com.sun.spring.component;import com.sun.spring.annotation.Component;
@Component(value = "monsterDao")
public class MonsterDao {public void hi() {System.out.println("MonsterDao say hi!");}}
3.修改MonsterService.java
package com.sun.spring.component;import com.sun.spring.annotation.Autowired;
import com.sun.spring.annotation.Component;
import com.sun.spring.annotation.Scope;@Scope(value = "prototype")
@Component(value = "monsterService")
public class MonsterService {@Autowiredprivate MonsterDao monsterDao;public void m1() {monsterDao.hi();}
}
4.修改SunSpringApplicationContext.java的createBean,添加依赖注入逻辑
private Object createBean(BeanDefinition beanDefinition){Class clazz = beanDefinition.getClazz();try {Object instance = clazz.getDeclaredConstructor().newInstance();for (Field field : clazz.getDeclaredFields()) {if (field.isAnnotationPresent(Autowired.class)) {String name = field.getName();Object bean = getBean(name);field.setAccessible(true);field.set(instance, bean);}}return instance;} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}}
5.启动类AppMain.java
package com.sxs.spring;import com.sxs.spring.aop.SmartAnimalable;
import com.sxs.spring.component.UserAction;
import com.sxs.spring.component.UserDao;
import com.sxs.spring.component.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppMain {public static void main(String[] args) {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");UserAction action1 = ioc.getBean(UserAction.class);UserAction action2 = ioc.getBean(UserAction.class);System.out.println("action1=" + action1);System.out.println("action2=" + action2);UserService service = ioc.getBean(UserService.class);System.out.println("service=" + service);service.m1();UserDao userDao = ioc.getBean(UserDao.class);System.out.println("userDao=" + userDao);SmartAnimalable bean = ioc.getBean(SmartAnimalable.class);bean.getSum(1,2);bean.getSub(2,1);}}
6.结果
3.总结IOC
1.单例bean的创建和依赖注入
- 获取Spring容器对象,读取配置文件,得到要扫描的包
- 扫描指定的包,将bean定义信息放到map中
- 初始化单例池,如果是单例的则直接反射创建bean对象并放到单例池中
- 依赖注入,扫描单例池中实例的所有字段,如果有自动装配注解则进行依赖注入
- 初始化bean对象
- getBean的时候从单例池中获取bean对象
- 销毁bean
2.多例bean的特殊处理
- getBean的时候反射创建bean对象,依赖注入,初始化bean,然后再得到bean对象
- 销毁bean