|
主要用到自定义注解、反射、dom4j的技术。不了解自定义注解的同学请搜索:深入理解Java:注解(Annotation)基本概念、深入理解Java:注解(Annotation)自定义注解入门、深入理解Java:注解(Annotation)--注解处理器 这3篇文章。
实现思路:
1、定义一个Map<String, Object> beanContainer用来存储bean。
2、xml中配置bean,<bean id="dao1" class="iocdemo.Dao1"></bean>,class属性值是类的全名,可通过反射创建实体类,id值作为key,实体类作为值存储在beanContainer中。
3、使用自定义注解@ComponentCustom标注类,通过 private Map<String, Object> componentBean(String scanPackage)方法扫描后将此类存放在beanContainer中
4、使用自定义注解@ResourceCustom标注成员变量,通过private void injectBean()方法注入实体类。
5、看不懂,没关系,Talk is cheap, I will show you the code.
demo目录结构

package iocdemo;
/**
* @Author:cpq
* @Description: 此类使通过xml配置到IOC中
*/
public class Dao1 {
public void show(){
System.out.println("Dao1的show方法*******1111****");
}
}
package iocdemo.scan;
import iocdemo.ComponentCustom;
/**
* @Author:cpq
* @Description: 通过注解加入到IOC容器中
*/
//@ComponentCustom(name = "dao222")
//@ComponentCustom("dao22")
@ComponentCustom
public class Dao2 {
private String name2;
public void show(){
System.out.println("Dao2的show方法*******2222****");
}
}
package iocdemo;
import iocdemo.scan.Dao2;
/**
* @Author:cpq
* @Description: 此类使通过xml配置到IOC中,并且通过注解@ResourceCustom注入成员变量的值
*/
public class Service1 {
//@ResourceCustom(name = "dao1")
//@ResourceCustom("dao1")
@ResourceCustom
private Dao1 dao1; //dao1在xml中配置了
//@ResourceCustom(name = "dao222")
//@ResourceCustom("dao22")
@ResourceCustom
private Dao2 dao2; //dao2使用了自定义注解
public void fieldMethod(){
dao1.show();
dao2.show();
}
}
此xml配置bean
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="dao1" class="iocdemo.Dao1"></bean>
<bean id="service1" class="iocdemo.Service1"></bean>
</beans>
自定义注解,类似于spring中的@component
package iocdemo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author:cpq
* @Description: 自定义注解
*/
//运行时执行
@Retention(RetentionPolicy.RUNTIME)
//用于描述类、接口(包括注解类型) 或enum声明
@Target({ElementType.TYPE})
public @interface ComponentCustom {
public String value() default "";
public String name() default "";
}
自定义注解,类似于JDK的@Resource
package iocdemo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author:cpq
* @Description:自定义注解
*/
//运行时执行
@Retention(RetentionPolicy.RUNTIME)
//适用于成员变量、方法
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface ResourceCustom {
public String value() default "";
public String name() default "";
}
工具类,可下载此demo运行public void t()方法测试。
package iocdemo;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import java.io.File;
import java.io.FileFilter;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @Author:cpq
* @Description: IOC工具类
*/
public class IOCUtil {
//ioc容器
Map<String, Object> beanContainer = new HashMap<String, Object>();
//使用dom4j读取xml配置的bean,并通过反射实例化bean
private Map<String, Object> xmlBean(String path){
try {
//classLoader.getResourceAsStream默认定位到classpath根目录,因为斜杠/也表示根目录,所以path不能以斜杠/开头。
InputStream is = this.getClass().getClassLoader().getResourceAsStream(path);
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(is);
Element beans = document.getRootElement();
for (Iterator<Element> beanList = beans.elementIterator(); beanList.hasNext();){
Element element = beanList.next();
//通过bean标签的class属性,用反射实例化bean
Object clazz = Class.forName(element.attributeValue("class")).newInstance();
//将bean的id、实例化的bean放到容器中
beanContainer.put(element.attributeValue("id"), clazz);
}
}catch (Exception e){
System.out.println("读取xml出错");
}
return beanContainer;
}
//扫描scanPackage包中的带有@ComponentCustom注解的类
private Map<String, Object> componentBean(String scanPackage){
try {
//获取扫描包路径
String path = this.getClass().getClassLoader().getResource(scanPackage.replaceAll("\\.","/")).getPath();
File dir = new File(path);
//目录不存在、非目录,beanContainer不新增bean,直接返回
if(!dir.exists() && !dir.isDirectory()){
return beanContainer;
}
//筛选出目录中以class结尾的文件
File[] files = dir.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".class");
}
});
for (File file: files){
//获取文件名,不包含后缀
String fileName = file.getName().split(".class")[0];
//反射获取创建类
Object clazz = Class.forName(String.format("%s.%s", scanPackage, fileName)).newInstance();
Class classObj = clazz.getClass();
//类是否有@ComponentCustom注解
if(classObj.isAnnotationPresent(ComponentCustom.class)){
//获取@ComponentCustom注解的参数值
ComponentCustom component = clazz.getClass().getAnnotation(ComponentCustom.class);
//判断@ComponentCustom(name = "dao2")、@ComponentCustom("dao2")、 @ComponentCustom()、@ComponentCustom这4种写法。使用@ComponentCustom这种写法时,类名首字母转小写后作为key
String name = !"".equals(component.name()) ?
component.name() : !"".equals(component.value()) ?
component.value() : fileName.substring(0,1).toLowerCase()+fileName.substring(1);
//实例化后的类放到容器中
beanContainer.put(name, clazz);
}
}
}catch (Exception e){
System.out.println("扫描目录失败");
}
return beanContainer;
}
//IOC容器中的bean,若其成员变量使用了@ResourceCustom且IOC中有这个类,则注入,详情请看:Service1这个类
private void injectBean(){
try {
for (String key: beanContainer.keySet()){
Object bean = beanContainer.get(key);
//获取所有成员变量
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field:fields){
//判断成员变量是否包含了@ResourceCustom注解
if(field.isAnnotationPresent(ResourceCustom.class)){
//获取@ResourceCustom注解的参数值
ResourceCustom resource = field.getAnnotation(ResourceCustom.class);
//判断@ResourceCustom(name = "dao1")、@ResourceCustom("dao1")、 @ResourceCustom()、@ResourceCustom这4种写法
String name = !"".equals(resource.name()) ?
resource.name() : !"".equals(resource.value()) ?
resource.value() : field.getName();
String beanId = name != "" ? name : field.getName();
//通过反射给私有成员赋值
field.setAccessible(true);
field.set(bean, beanContainer.get(beanId));
}
}
}
}catch (Exception e){
System.out.println("bean属性注入失败");
}
}
//获取IOC容器中的bean
public Object getBean(String id){
//读取xml中的bean
xmlBean("iocdemo/bean.xml");
//扫描包中带有@ComponentCustom注解的bean
componentBean("iocdemo.scan");
//使用了@ResourceCustom注解的成员变量注入值(值为实例化后的类)
injectBean();
//返回IOC容器中的类
return beanContainer.get(id);
}
//运行此方法测试
@Test
public void t(){
Service1 s = (Service1) getBean("service1");
s.fieldMethod();
}
}
demo链接
度盘:https://pan.baidu.com/s/1kWc61PP(不推荐使用)
CSDN:http://download.csdn.net/download/u010606397/10203730(墙裂推荐使用)
|