在前面的文章中我们讲述了Spring的基本概念和及IOC和AOP在这篇文章中我们来模拟实现Spring的IOC操作
(1)关于模拟实现IOC我们主要实现两个功能
- 控制反转:用框架来创建对象
@Test
public void testService(){
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
UserService userservice = context.getBean("userService", UserService.class);
userservice.add();
}
- 依赖注入:用框架来注入属性
@Component(singleton = false)
public class ClassOne {
@Autowired
private Complex complex;
@Autowired
private Point point;
}
(2)实现原理
- 控制反转:构建一个容器(上下文),在使用框架前,先扫描工程所有的类,看其是否需要通过框架生成对象(给类加Component注解)。如果是则在这个容器中存储类及其对象;在用框架创建这些类的对象时,基本上都是从这个容器中获取的;这些类的属性,若其类型也在容器中,则,它们将被自动初始化,且用容器中的对象完成初始化。判断哪些类可以放置在容器容有两种方式,注解或XML配置文件。本次实现使用注解方式。
- 在实现控制反转时设置对象是单例,或是非单例,可以在Component注解中加singleton参数实现。如果是单例,则在扫描包时生成对象,否则在getBean时生成
- 依赖注入:在类的属性上添加Autowired注解,判断其是否需要自动注入,如果是,则从容器中获取该属性的对象对其注入。
-
在注入的时候,可能会出现循环依赖,这个问题可以通过在注入属性前将inject设为true打破这个循环得以解决。
Component注解
@Retention(RUNTIME)
@Target(TYPE)
public @interface Component {
boolean singleton() default true;//默认储存单例对象
}
Autowired注解
@Retention(RUNTIME)
@Target({ FIELD, METHOD })
public @interface Autowired {
}
(3)代码实现
- BeanDefinition:类的模型, 包含类的元数据类,类的对象,是否单例和是否需要注入
public class BeanDefinition {
private Class<?> klass;
private Object object;
private boolean singleton;
private boolean inject;
BeanDefinition() {
this.inject = false;
this.singleton = true;
}
boolean isSingleton() {
return singleton;
}
void setSingleton(boolean singleton) {
this.singleton = singleton;
}
boolean isInject() {
return inject;
}
void setInject(boolean inject) {
this.inject = inject;
}
Class<?> getKlass() {
return klass;
}
void setKlass(Class<?> klass) {
this.klass = klass;
}
Object getObject() {
return object;
}
void setObject(Object object) {
this.object = object;
}
}
- BeanFactory:核心类,扫描指定包,获取需要放入容器(beanpool)的类(bean)
public class BeanFactory {
//容器
private static final Map<String, BeanDefinition> beanPool;
static {
beanPool = new HashMap<String, BeanDefinition>();
}
public BeanFactory() {
}
//包扫描
public void scanBeanByPackage(String packageName) {
new PackageScanner() {
@Override
//得到带有Component的类
public void dealClass(Class<?> klass) {
if (klass.isPrimitive()
|| klass.isInterface()
|| klass.isAnnotation()
|| klass.isEnum()
|| klass.isArray()
|| !klass.isAnnotationPresent(Component.class)) {
return;
}
try {
//生成类对象,并放入容器中
Object object = null;
Component component = klass.getAnnotation(Component.class);
boolean singleton = component.singleton();
BeanDefinition beanDefinition = new BeanDefinition();
if (singleton) {
object = klass.newInstance();
}
beanDefinition.setSingleton(singleton);
beanDefinition.setKlass(klass);
beanDefinition.setObject(object);
beanPool.put(klass.getName(), beanDefinition);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}.scanPackage(packageName);
}
BeanDefinition getBeanDefinition(String klassName) {
return beanPool.get(klassName);
}
BeanDefinition getBeanDefinition(Class<?> klass) {
return getBeanDefinition(klass.getName());
}
private void injectProperties(BeanDefinition beanDefinition) throws RuntimeException {
Class<?> klass = beanDefinition.getKlass();
Object object = beanDefinition.getObject();
Field[] fields = klass.getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(Autowired.class)) {
continue;
}
// 应该先对inject进行判断,若为true,表示该对象已经完成注入;
// 这种方法可以避免循环依赖。
field.setAccessible(true);
Object value = getBean(field.getType());
if (value == null) {
throw new HasNoBeanException("类[" + klass.getName()
+ "]的[" + field.getName()
+ "]成员没有对应的Bean!");
}
try {
field.set(object, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
private static BeanDefinition getBeanObject(String className) {
BeanDefinition bean = beanPool.get(className);
if (bean == null) {
return null;
}
Object object = null;
if (!bean.isSingleton()) {
Class<?> klass = bean.getKlass();
try {
object = klass.newInstance();
bean.setObject(object);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return bean;
}
@SuppressWarnings("unchecked")
public <T> T getBean(String klassName) throws RuntimeException {
BeanDefinition bean = getBeanObject(klassName);
if (bean == null) {
System.out.println("Bean[" + klassName + "]不存在!");
return null;
}
Object object = bean.getObject();
if (!bean.isInject() || !bean.isSingleton()) {
bean.setInject(true);
// 这里完成对object中需要注入的成员的初始化工作!
injectProperties(bean);
}
return (T) object;
}
public <T> T getBean(Class<?> klass) throws RuntimeException {
return getBean(klass.getName());
}
}
(4)测试
- 默认单例的控制反转
@Component
public class ClassOne {
public ClassOne() {
System.out.println("ClassOne...");
}
}
public class Demo {
public static void main(String[] args) {
BeanFactory beanFactory = new BeanFactory();
beanFactory.scanBeanByPackage("some_class");
ClassOne classOne = beanFactory.getBean(ClassOne.class);
}
}
2. 非单例控制反转
@Component(singleton = false)
public class ClassOne {
public ClassOne() {
System.out.println("ClassOne...");
}
}
public class Demo {
public static void main(String[] args) {
BeanFactory beanFactory = new BeanFactory();
beanFactory.scanBeanByPackage("some_class");
ClassOne classOne = beanFactory.getBean(ClassOne.class);
System.out.println("classOne-->" + classOne + "classOne.hashCode()-->" + classOne.hashCode());
ClassOne classOne2 = beanFactory.getBean(ClassOne.class);
System.out.println("classOne2-->" + classOne2 + "classOne2.hashCode-->" + classOne2.hashCode());
}
}
- 注入属性
@Component
public class ClassTwo {
public ClassTwo() {
System.out.println("ClassTwo...");
}
@Autowired
public ClassOne classone;
}
public class Demo {
public static void main(String[] args) {
BeanFactory beanFactory = new BeanFactory();
beanFactory.scanBeanByPackage("some_class");
ClassTwo classtwo = beanFactory.getBean(ClassTwo.class);
}
}
- 循环依赖的属性注入
@Component
public class ClassTwo {
public ClassTwo() {
System.out.println("ClassTwo...");
}
@Autowired
public ClassOne classone;
}
@Component(singleton = false)
public class ClassOne {
public ClassOne() {
System.out.println("ClassOne...");
}
@Autowired
public ClassTwo classtwo;
}
public class Demo {
public static void main(String[] args) {
BeanFactory beanFactory = new BeanFactory();
beanFactory.scanBeanByPackage("some_class");
ClassTwo classtwo = beanFactory.getBean(ClassTwo.class);
}
}
版权声明:本文为weixin_45430915原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。