Spring初探之bean工厂(下)

上一部分简单演示使用xml配置下spring对bean的管理,这回不用xml配置,直接在java代码中使用注解,spring又是如何管理bean的?首先在Demo类的头部增加@Component注解,代码如下:

import org.springframework.stereotype.Component;

@Component(value="demo")
public class Demo {
//这里略去部分代码
}


其次,修改原先的xml配置“<bean id="demo" class="com.jvk.ken.spring.Demo" />”为“<context:component-scan base-package="com.jvk.ken.spring" />”,其它部分不作修改,运行测试代码,可知两种配置形式达到的效果完全一致。那spring是如何通过注释把javabean管理起来的呢?这里写一个简单的类来模拟spring的工厂类,代码如下:

package com.jvk.ken.spring;

import java.io.File;
import java.io.FileFilter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Component;

public class MyBeanFactory {
	// 保存bean的定义
	Map<String, Class> beans = new HashMap<String, Class>();

	public Object getBean(String id) throws Exception {
		Class class1 = beans.get(id);
		Constructor declaredConstructor = class1.getDeclaredConstructor();
		declaredConstructor.setAccessible(true);
		return declaredConstructor.newInstance();
	}

	private String xmlFile;

	public MyBeanFactory(String xmlFile) throws Exception {
		super();
		this.xmlFile = xmlFile;
		init();
	}

	private void init() throws Exception {
		// 初始化与解析XML,这里略去实际解析XML的情况,使用硬编码模仿
		System.out.println("配置文件:" + xmlFile);
		String basePkg = "com.jvk.ken.spring";
		System.out.println("根据配置,描述注解的包为" + basePkg);

		Enumeration<URL> resources = Thread.currentThread()
				.getContextClassLoader()
				.getResources(basePkg.replace('.', '/'));
		while (resources.hasMoreElements()) {
			URL url = resources.nextElement();
			String protocol = url.getProtocol();
			// 如果是以文件的形式保存在服务器上,这里不考虑jar包或其它形式的引用
			if ("file".equals(protocol)) {
				// 获取包的物理路径
				String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
				// 获取包下的所有class文件,这里不考虑目录递归查找
				File[] classFiles = new File(filePath)
						.listFiles(new FileFilter() {
							public boolean accept(File file) {
								return file.getName().endsWith(".class");
							}
						});

				for (File f : classFiles) {
					String filename = f.getName();
					String className = filename.substring(0,
							filename.length() - 6);
					Class<?> loadClass = this.getClass().getClassLoader()
							.loadClass(basePkg + '.' + className);
					Annotation[] annotations = loadClass.getAnnotations();
					for (Annotation a : annotations) {
						if (a instanceof Component) {
							String beanId = ((Component) a).value();
							beans.put(beanId, loadClass);
							break;
						}
					}

				}

			}
		}

	}
}


运行下面的测试代码,可以看到MyBeanFactory确实达到spring的类似的效果。

MyBeanFactory bf = new MyBeanFactory("applicationContext.xml");
		Demo bean = (Demo) bf.getBean("demo");
		System.out.println(bean.getClass());
		bean.printName();


至此,已经演示完spring为我们创建bean的基本原理了。但spring能做到的远比演示的内容要多,比如通过构造方法注入初始值,通过setter方法注入字面值或其它bean实例,还可以为bean的方法增加前置拦截方法,后置拦截方法和异常拦截方法等等。这些神奇的功能spring又是怎样做到的?下一篇将分析这些内容,特别解构一下spring的声明式事务有什么秘密。

 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值