1、整体的目录:
首先定义一个类扫描器:
2、ClassScanner
package cn.com.hsl.webEE.utils;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassScanner {
public static Map<String, Class<?>> scan(String pkg) {
Map<String, Class<?>> result = new HashMap<String, Class<?>>();
String basePath = pkg;
if (pkg.contains(".")) {
basePath = pkg.replace(".", "/");
}
Enumeration<URL> urls;
try {
urls = Thread.currentThread().getContextClassLoader().getResources(basePath);
while (urls.hasMoreElements()) {
URL url = (URL) urls.nextElement();
//如果是本地的文件
if ("file".equals(url.getProtocol())) {
File folder = new File(url.getPath());
scanFolder(pkg, folder, result);
//如果是Jar包的文件
} else if ("jar".equals(url.getProtocol())) {
scanjar(url, basePath, result);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
private static void scanFolder(String root, File folder, Map<String, Class<?>> result) {
for (File file : folder.listFiles()) {
String name = file.getName();
if (file.isDirectory()) {
scanFolder(root + "." + name, file, result);
} else {
try {
//只扫描以 .class 结尾的文件
if (!name.endsWith(".class")) {
continue;
}
String className = name.substring(0, name.lastIndexOf("."));
//不掃描內部類
if (className.matches("[\\w+$*\\w*/]+\\$\\d+$")) {
continue;
}
String classPath = root + "." + className;
result.put(className, Class.forName(classPath));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
private static void scanjar(URL url, String basePath, Map<String, Class<?>> result) throws IOException {
JarURLConnection connection = (JarURLConnection) url.openConnection();
if (connection != null) {
JarFile jarFile = connection.getJarFile();
if (jarFile != null) {
//Jar包获取的将是这个jar包中的全部文件
Enumeration<JarEntry> entryEnu = jarFile.entries();
while (entryEnu.hasMoreElements()) {
JarEntry jarEntry = (JarEntry) entryEnu.nextElement();
String entryClass = jarEntry.getName();
if (entryClass == null || !entryClass.endsWith(".class")){
continue;
}
String entryName = entryClass.substring(0, entryClass.lastIndexOf("."));
if (entryName.matches("[\\w+$*\\w*/]+\\$\\d+$")) {
continue;
}
//需要过滤其他包目录下的文件
if (entryName.startsWith(basePath)) {
try {
result.put(entryName, Class.forName(entryName.replace("/", ".")));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
}
public static void main(String[] args) {
Map<String, Class<?>> classMap = ClassScanner.scan("cn");
System.out.println(classMap);
}
}
其次定义一些注解:
3.1、Autowired
package cn.com.hsl.webEE.annotation;
import static java.lang.annotation.ElementType.FIELD;
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, FIELD })
public @interface Autowired {
//注入的Bean实例
String value();
}
3.2、Bean
package cn.com.hsl.webEE.annotation;
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 Bean {
//Bean在容器中的名称
String value();
//是否是单例
boolean single() default true;
}
定义一些实体类,这些实体类用来保存 在多例的时候 类和属性的相关信息:
4.1、BeanEntity
package cn.com.hsl.webEE.entity;
import java.util.ArrayList;
import java.util.List;
public class BeanEntity {
private String beanName;
private String className;
private Class<?> clazz;
private List<FieldEntity> fields = new ArrayList<FieldEntity>();
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public Class<?> getClazz() {
return clazz;
}
public void setClazz(Class<?> clazz) {
this.clazz = clazz;
}
public List<FieldEntity> getFields() {
return fields;
}
public void setFields(List<FieldEntity> fields) {
this.fields = fields;
}
}
4.2、FieldEntity
package cn.com.hsl.webEE.entity;
import java.lang.reflect.Field;
public class FieldEntity {
private Field field;
private String beanName;
public Field getField() {
return field;
}
public void setField(Field field) {
this.field = field;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}
封装Bean工厂:
4、ApplicationContext
package cn.com.hsl.webEE.core;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import cn.com.hsl.webEE.annotation.Autowired;
import cn.com.hsl.webEE.annotation.Bean;
import cn.com.hsl.webEE.entity.BeanEntity;
import cn.com.hsl.webEE.entity.FieldEntity;
import cn.com.hsl.webEE.utils.ClassScanner;
public class ApplicationContext {
private Map<String, Class<?>> classMap;
//单例Bean容器
private Map<String, Object> beans = new HashMap<String, Object>();
//多例Bean容器
private Map<String, BeanEntity> entities = new HashMap<String, BeanEntity>();
public ApplicationContext(String pkg) {
init(pkg);
}
private void init(String pkg) {
this.classMap = ClassScanner.scan(pkg);
for (Entry<String, Class<?>> entry : classMap.entrySet()) {
//String beanName = entry.getKey();
Class<?> beanClass = entry.getValue();
if (beanClass.isAnnotationPresent(Bean.class)) {
initBean(beanClass);
}
}
}
private Object initBean(Class<?> clazz) {
Object obj = null;
try {
Bean bean = clazz.getAnnotation(Bean.class);
String beanName = bean.value();
//如果是单例
if(bean.single()) {
if (beans.containsKey(beanName)) {
return beans.get(beanName);
}
obj = initSigleBean(clazz);
beans.put(beanName, obj);
//如果是多例,只是保存BeanEntity
} else {
initMultBean(beanName, clazz);
}
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
private Object initSigleBean(Class<?> clazz) throws Exception {
Object obj = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
Autowired autowired = field.getAnnotation(Autowired.class);
String fieldBeanName = autowired.value();
//从容器中去拿,如果有直接使用,如果没有,先去创建,再使用
Object o = getBean(fieldBeanName);
if (o == null) {
//如果这个field是多例的,则没有返回具体的实例,而是一个beanEntity
o = initBean(field.getType());
//这时需要再次获取一次,实例化一下。
if (o == null) {
o = getBean(fieldBeanName);
}
}
field.setAccessible(true);
field.set(obj, o);
}
}
return obj;
}
private void initMultBean(String beanName, Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
BeanEntity beanEntity = new BeanEntity();
beanEntity.setBeanName(beanName);
beanEntity.setClazz(clazz);
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
Autowired autowired = field.getAnnotation(Autowired.class);
FieldEntity fieldEntity = new FieldEntity();
fieldEntity.setBeanName(autowired.value());
fieldEntity.setField(field);
beanEntity.getFields().add(fieldEntity);
}
}
entities.put(beanName, beanEntity);
}
public Object getBean(String beanName) throws Exception {
Object obj = null;
obj = beans.get(beanName);
if (obj == null) {
if (entities.containsKey(beanName)) {
BeanEntity beanEntity = entities.get(beanName);
Class<?> clazz = beanEntity.getClazz();
if (clazz != null) {
obj = clazz.newInstance();
List<FieldEntity> fieldEntities = beanEntity.getFields();
for (FieldEntity fieldEntity : fieldEntities) {
Field field = fieldEntity.getField();
field.setAccessible(true);
field.set(obj, getBean(fieldEntity.getBeanName()));
}
}
}
}
return obj;
}
}
测试:
5.1、UserDao
package cn.com.hsl.webEE;
import cn.com.hsl.webEE.annotation.Bean;
@Bean("userDao")
public class UserDao {
public void addUser() {
System.out.println(this.getClass().getName() + ".addUser().");
}
}
5.2、UserService
package cn.com.hsl.webEE;
import cn.com.hsl.webEE.annotation.Autowired;
import cn.com.hsl.webEE.annotation.Bean;
@Bean("userservice")
public class UserService {
@Autowired("userDao")
private UserDao userDao;
public void add() {
userDao.addUser();
}
}
5.3、App
package cn.com.hsl.webEE;
import cn.com.hsl.webEE.core.ApplicationContext;
/**
* Hello world!
*
*/
public class App {
public static void main(String[] args) {
try {
ApplicationContext context = new ApplicationContext("cn.com.hsl");
UserService userService = (UserService) context.getBean("userservice");
userService.add();
} catch (Exception e) {
e.printStackTrace();
}
}
}