紧接着上一篇spring依赖注入xml配置原理解析,本文实现了使用注解的配置方式注入bean,大致分为以下几步:
1)解析xml文件,获取需要扫描的包
2)递归获取这些包下及其子包下所有的java类(此时真正扫描的是.class文件)
3)将所有标识有Service,Repository注解的类进行实例化,并将这些类中需要注入的属性进行保存
4)对bean的属性进行注入
具体实现方式如下:
1.添加相关依赖:
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
2.自定义注解
/**
* 定义注解的存在范围,共三种,详情请参考JDK API(1.5版本及以后)中的RetentionPolicy
*/
@Retention(RetentionPolicy.RUNTIME)
/**
* 定义注解的使用范围,共有8种,详情请参考JDK API(1.5版本及以后)中的ElementType
*/
@Target(ElementType.TYPE)
/**
* 指示注释类型被自动继承,详情请参考JDK API(1.5版本及以后)中的Inherited
*/
@Inherited
//自定义Service层注解
public @interface Service {
//用于保存Service的id,默认为空字符
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
//自定义Dao层注解
public @interface Repository {
//用于保存Service的id,默认为空字符
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.FIELD,ElementType.METHOD})
public @interface Inject {
String value() default "";
}
public class AnnotationUtil {
private static final AnnotationUtil util = new AnnotationUtil();
//保存xml文件配置的所有的包名
private List<String> basePackages = new ArrayList<String>();
//保存需扫描的包及其子包下所有的类的全限定名
private List<String> clzNames = new ArrayList<String>();
//保存需扫描的包下及其子包下标识有Service和Repository的全限定类名,key为这个bean解析出的id,value为全限定类名
private Map<String,String> annotationClzNames = new HashMap<String, String>();
//类路径
private final String classesPath = AnnotationUtil.class.getClassLoader().getResource("").getPath();
//保存扫描到的类的Service和Repository注解的value值和class,id为注解的value()值,value为反射获得的实例
private Map<String,Object> beans = new HashMap<String,Object>();
//保存bean的id和其需要注入的字段及该字段需要注入的bean的id
private Map<String,Map<String,String>> propertys = new HashMap<String,Map<String,String>>();
private SAXReader reader;
private Document document;
private AnnotationUtil(){
reader = new SAXReader();
}
public static AnnotationUtil getInstance(){
return util;
}
public Map<String,Object> parseXml(String xmlPath) throws DocumentException{
document = reader.read(new File(xmlPath));
//解析xml文档
this.parseComponent(document);
//获取xml配置的包下的所有类
this.scanClass();
//遍历所有的类,并将有Service,Repository注解标识的类实例化放进beans当中
this.InteratorClass();
//遍历所有标识有Service和Repository注解的类进行属性注入
this.InjectBean();
return beans;
}
/**
* 解析xml文档中的component-scan节点,保存所有的包名
* @param document
*/
@SuppressWarnings("unchecked")
public void parseComponent(Document document){
if(document==null){
return;
}
//获取根元素beans
Element ele = document.getRootElement();
//使用xpath表达式查找所有的component-scan节点
List<Element> beanElements = ele.selectNodes("//beans/component-scan");
if(beanElements==null||beanElements.size()==0){
return;
}
String basePackage = null;
//遍历所有的component-scan节点
for(Element beanElement:beanElements){
basePackage = beanElement.attributeValue("base-package");
if(basePackage==null||basePackages.contains(basePackage)){
continue;
}
basePackages.add(basePackage);
}
}
//获得配置的包下的所有类
private void scanClass(){
if(basePackages.size()==0){
return ;
}
//保存一个包下的类名
List<String> everyPackageClzNames = null;
for(String basePackage:basePackages){
//将每一个包下的类名进行保存
everyPackageClzNames = scanClassFile(basePackage);
clzNames.addAll(everyPackageClzNames);
}
}
//递归获取某个包下的所有类
private List<String> scanClassFile(String path){
//将包名.转换为路径/,跟类路径进行拼接
String packagePath = classesPath+path.replaceAll("\\.", "/");
File file = new File(packagePath);
List<String> clzPaths= new ArrayList<String>();
if(!file.exists()){
return clzPaths;
}
File[] files = file.listFiles(new FilenameFilter() {
//获取该包下的子包和.class文件
@Override
public boolean accept(File dir, String name) {
return dir.isDirectory()||name.endsWith(".class");
}
});
if(files.length==0){
return clzPaths;
}
for(File f:files){
if(f.isFile()){
//保存全限定类名(包名+类名)
clzPaths.add(path+"."+f.getName().substring(0, f.getName().length()-6));
}else if(f.isDirectory()){
//如果是目录就进行递归
clzPaths.addAll(scanClassFile(path+"."+f.getName()));
}
}
return clzPaths;
}
private void InteratorClass(){
if(clzNames.size()==0){
return;
}
Class<?> clz = null;
Service service = null;
Repository repository = null;
Inject inject = null;
//保存注解的value值,如果是默认值,就让idValue为类名首字母小写形式当做beans的key
String idValue = null;
//用于标记这个注解是否是Service和Repository当中的一个
boolean flag = false;
for(String clzName:clzNames){
try {
clz = Class.forName(clzName);
//如果这个类是接口或者抽象类就跳过
if(clz.isInterface()||Modifier.isAbstract(clz.getClass().getModifiers())){
continue;
}
Annotation[] classAnnotations = clz.getAnnotations();
for(Annotation annotation:classAnnotations){
//判断是Service注解还是Repository注解
if(annotation instanceof Service){
service = (Service)annotation;
idValue = service.value();
flag = true;
break;
}else if(annotation instanceof Repository){
repository = (Repository)annotation;
idValue = repository.value();
flag = true;
break;
}
}
//当这个注解是Service和Repository当中的一个的时候,才执行一下操作
if(flag){
//如果没有指定id值(即给注解的value赋值),则默认id为类名首字母小写形式
if("".equals(idValue)){
//此时获取的是类名
idValue = clz.getSimpleName();
//转化为首字母小写
idValue = idValue.substring(0, 1).toLowerCase()+idValue.substring(1);
}
//判断该类是否已经被实例化
if(beans.containsKey(idValue)){
throw new RuntimeException("The class "+clzName+ " has already been instantiated");
}
//如果flag为true,说明这个类被标识了Service和Repository其中的一个注解
annotationClzNames.put(idValue,clzName);
beans.put(idValue, clz.newInstance());
//保存那个字段需要注入
String fieldName = null;
//获取这个类声明的所有字段
Field[] fields = clz.getDeclaredFields();
//保存这个类里面有哪些字段需要注入,key为需要注入的字段名,value为需要注入的bean的id值
Map<String,String> map = null;
for(Field field:fields){
Annotation[] fieldAnnotations = field.getDeclaredAnnotations();
map = new HashMap<String,String>();
for(Annotation annotation:fieldAnnotations){
//判断该属性是否标识有Inject注解
if(annotation instanceof Inject){
inject = (Inject)annotation;
fieldName = inject.value();
//如果为空,默认以属性名进行注入
if("".equals(fieldName)){
fieldName = field.getName();
}
map.put(fieldName, fieldName);
}
}
}
if(map!=null&&!map.isEmpty()){
propertys.put(idValue, map);
}
//执行完了之后再重置flag
flag = false;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("rawtypes")
private void InjectBean() {
if(annotationClzNames.size()==0){
return;
}
Class<?> clz = null;
Inject inject = null;
String idValue = null;
Set<String> keys = annotationClzNames.keySet();
for(String key:keys){
try {
//根据全限定类名获取Class
clz = Class.forName(annotationClzNames.get(key));
//获取该类声明的所有字段
Field[] fields = clz.getDeclaredFields();
for(Field field:fields){
Annotation[] annotations = field.getDeclaredAnnotations();
for(Annotation annotation:annotations){
//判断该属性是否标识有Inject注解
if(annotation instanceof Inject){
inject = (Inject)annotation;
idValue = inject.value();
//如果为空,默认以属性名进行注入
if("".equals(idValue)){
idValue = field.getName();
}
//如果该字段为private或者protected修饰的,则必须要设置可以访问
field.setAccessible(true);
//根据key获得这个类的已经实例化的对象,然后对该的字段进行注入
field.set(beans.get(key),beans.get(((Map)propertys.get(key)).get(idValue)));
break;
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
public interface IUserDao {
void addUser();
}
@Repository("UserDao")
public class UserDao implements IUserDao{
@Override
public void addUser() {
System.out.println("进行了新增操作");
}
}
public interface IUserService {
void addUser();
}
@Service
public class UserService implements IUserService{
//属性注入
@Inject("UserDao")
private IUserDao userDao;
@Override
public void addUser() {
userDao.addUser();
}
}
5.配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<component-scan base-package="cn.edu.hbut.zw.spring" />
</beans>
6.测试
public class SpringTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
IUserService us = (IUserService) context.getBean("userService");
us.addUser();
}
}