本篇博文并不是讲Spring的,而是模拟Spring,比如说以前笔者写过的包扫描工具,就可以在此时起到用场。
Spring最基本的两个功能:IOC 、AOP。
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)
控制反转 将创建对象的权利 反转给了Spring
AOP为 Aspect Oriented Programming 的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
什么叫依赖?
class B{
private A a; //B类依赖于A类
}
有关对IOC的理解,推荐一个文章 IoC 之 2.1 IoC基础 ——跟我学Spring3
本篇博文主要的是 如何注入
首先给出两个注解(xml解析会更好,不用改java代码)
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(FIELD)
public @interface Autowired
{
// 注解属性的默认值不能是null
String name() default "";
}
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(TYPE)
public @interface Component
{
String name() default "";
// singelton用在类前,代表是否单例,默认是单例singelton=true;
boolean singelton() default true;
}
给出两个javaBean
import annotation.Component;
// javaBean
@Component
public class Complex
{
private double real;
private double vir;
public Complex()
{
}
public double getReal()
{
return real;
}
public void setReal(double real)
{
this.real=real;
}
public double getVir()
{
return vir;
}
public void setVir(double vir)
{
this.vir=vir;
}
@Override
public String toString()
{
return "Complex [" + real + ", " + vir + "]";
}
}
import annotation.Autowired;
import annotation.Component;
// javaBean
@Component
public class ClassOne
{
// Autowired后跟的name,需要注入谁,就跟谁
@Autowired
private Complex complex;
// 给八大基本类型上autowired意义不大
private String str;
public ClassOne()
{
// TODO 自动生成的构造函数存根
}
public Complex getComplex()
{
return complex;
}
public void setComplex(Complex complex)
{
this.complex=complex;
}
public String getStr()
{
return str;
}
public void setStr(String str)
{
this.str=str;
}
@Override
public String toString()
{
return "ClassOne [" + complex + ", " + str + "]";
}
}
接下来是 注入 的核心所在,另外还有 PackageScanner.java,HasNoBeanException.java 需要读者补充
public class BeanDefinition
{
private Class<?> klass;
private Object object;// 用来取对象
private boolean inject;// 判断是否注入
// 应该给出包权限,给Spring内部用
BeanDefinition()
{
this.inject=false;
}
public boolean isInject()
{
return inject;
}
public void setInject(boolean inject)
{
this.inject=inject;
}
public Class<?> getKlass()
{
return klass;
}
public void setKlass(Class<?> klass)
{
this.klass=klass;
}
public Object getObject()
{
return object;
}
public void setObject(Object object)
{
this.object=object;
}
@Override
public String toString()
{
return "BeanDefinition [klass=" + klass + ", object=" + object + "]";
}
}
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import annotation.Autowired;
import annotation.Component;
import scanner.PackageScanner;
// Bean工厂中的Bean,都是单例的。如果想多例,必须加以声明
public class BeanFactory
{
private static final Map<String, BeanDefinition> beanpool;
static
{
beanpool=new HashMap<String, BeanDefinition>();
}
public BeanFactory()
{
// TODO 自动生成的构造函数存根
}
// 把相应的东西扫描到beanPool里面
public static void scanBeanByPackage(String packageName)
{
new PackageScanner()
{
@Override
public void dealClass(Class<?> klass)
{
if(klass.isPrimitive() || klass.isInterface() || klass.isAnnotation() || klass.isEnum() || klass.isArray()
|| !klass.isAnnotationPresent(Component.class))
{
return;// 不处理以上类
}
try
{
Object object=klass.newInstance();
BeanDefinition bd=new BeanDefinition();
bd.setKlass(klass);
bd.setObject(object);
beanpool.put(klass.getName(), bd);
}
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 Exception
{
Class<?> klass=beanDefinition.getKlass();
Object object=beanDefinition.getObject();
Field[] fields=klass.getDeclaredFields();
for(Field field : fields)
{
// 检测成员是否需要注入
if(!field.isAnnotationPresent(Autowired.class))
{
continue;
}
field.setAccessible(true);// 保证成员能够被赋值,权限
// 取出以该成员类型作为Bean关键字的对象
Object value=getBean(field.getType());
if(value == null)
{
throw new HasNoBeanException("类[" + klass.getName() + "]的[" + field.getName() + "]成员没有对应的Bean");
}
field.set(object, value);
System.out.println("注入过程");
}
beanDefinition.setInject(true);// 表示已经注入完毕
}
// 用泛型使用方便
public <T> T getBean(String klassName) throws RuntimeException
{
BeanDefinition bd=getBeanDefinition(klassName);
if(bd == null)
{
return null;
}
Object result=bd.getObject();
// 如果没有注入了,那就注入
if(!bd.isInject())
{
try
{
injectProperties(bd);
}
catch(Exception e)
{
e.printStackTrace();
}
}
return (T) result;
}
public <T> T getBean(Class<T> klass) throws RuntimeException
{
return getBean(klass.getName());
}
}
- 从运行结果的第三行:true,表明了Bean工厂中的Bean,都是单例的!
- 第四行可以看出我们成功实现注入:
将Java Bean(Complex.java)组织到一个容器中,就形成所谓的“上下文”或者容器。 - 模拟实现时采用“懒汉模式”,即只有相关的Bean在被 getBean() 时,才需要注入。
- 大家可以试着把 Complex.java 的 @Component 去掉,通过自定义异常的方式来处理。