容器式单例自定义工厂(模拟spring容器)

工具类作用:
1.根据配置文件反射创建类对象存入容器,
2.根据对象里的自动装配注解,定义成员对象

一:配置文件配置类的全限定名
配置好的类会用工具类存储到map容器中

<beans>
<bean id="UserService" className="com.alibaba.service.impl.UserServiceImpl"></bean>
<bean id="UserDao" className="com.alibaba.dao.UserDaoImpl.UserDaoImpl"></bean>
</beans>

二:自定义工厂工具类
1.解析xml配置文件
2.为配置文件配置的类创建对象存入map
3.根据注解为容器里的对象的成员对象赋值(初始化)
4.根据参数返回对象的方法

package com.alibaba.utils;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author:ZZZ
 * @Date: 2020/12/24 15:51
 * @Version 1.0
 */
public class Factory {
    //容器Map
    static Map <String, Object> containerMap = new HashMap();
    static {
//读取bean的xml配置文件
        InputStream is = Factory.class.getClassLoader().getResourceAsStream("Simulate_Spring.xml");
        SAXReader saxReader = new SAXReader();
        try {
            //dom4j将整个配置文件成Document对象
            Document document = saxReader.read(is);
           // List<Element> list = document.selectNodes("//bean");
            //Document读取根节点
            Element rootElement = document.getRootElement();
            //通过根节点拿到所有的配置文件的子节点 <bean id="" class=""  />
            List <Element> elements = rootElement.elements();
            //将配置的所有内容都实例化对象
            for (Element element : elements) {
                //对象名字
                String id = element.attributeValue("id");
                //类的全限定名
                String className = element.attributeValue("className");
                System.out.println(id+":"+className);
                //类Class对象
                Class<?> aClass = Class.forName(className);
                //反射创建对象
                Object obj = aClass.newInstance();
                //存入容器
                containerMap.put(id,obj);
            }
            //遍历容器将带有autowired的注解的成员初始化
            for (Map.Entry<String, Object> entry : containerMap.entrySet()) {
//                对象
                Object objectClass = entry.getValue();
//               对象的成员变量
                Field[] declaredFields = objectClass.getClass().getDeclaredFields();
                for (Field declaredField : declaredFields) {

//                    对象的每个成员变量
//                    成员变量上的注解
                    for (Annotation declaredAnnotation : declaredField.getDeclaredAnnotations()) {
//                        注解上有自动装配
                        if (declaredAnnotation.toString().equals("@com.alibaba.annotation.MyAutoWired()")) {
                            //                    将当前成员变量第一个字母大写
                            char[] chars = declaredField.getName().toCharArray();
                            chars[0]-=32;
                            String strDeclaredField = new String(chars);
                            declaredField.set(objectClass,getObject(strDeclaredField));
                        }
                    }
                }
            }
    }
    catch (Exception e){
        e.printStackTrace();
        }
    }

    //工厂获取对象
   public static Object getObject(String id) {
        try {
            Object obj = containerMap.get(id);
           if (obj != null) {
                //容器中有该对象
                return obj;
            } else {
               throw new RuntimeException("容器找不到该对象");
            }
        } catch (Exception e) {
          return null;
       }
    }
}

自定义注解
作用:为了工具类实现自动装配

package com.alibaba.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author:ZZZ
 * @Date: 2021/1/4 15:41
 * @Version 1.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface MyAutoWired {

}

UserServiceImpl:
该类的方法调用了UserDao的方法,用自定义注解实现自动装配成员userDao
接口略

package com.alibaba.service.impl;

import com.alibaba.User;
import com.alibaba.annotation.MyAutoWired;

import com.alibaba.dao.UserDao;
import com.alibaba.service.UserService;
import com.alibaba.utils.Factory;

/**
 * @Author:ZZZ
 * @Date: 2020/12/24 15:42
 * @Version 1.0
 */
public class UserServiceImpl implements UserService {

    @MyAutoWired
    public UserDao userDao ;

    @Override
    public User findById(int id) {
       return  userDao.findById(id);
    }
}

UserDaoImpl
接口略


package com.alibaba.dao.UserDaoImpl;

import com.alibaba.User;
import com.alibaba.dao.UserDao;

/**
 * @Author:ZZZ
 * @Date: 2020/12/24 15:44
 * @Version 1.0
 */
public class UserDaoImpl implements UserDao {
    @Override
    public User findById(int id) {
        System.out.println("查询User");
        return new User();
    }
}

测试类
从容器里拿UserServiceImpl,UserServiceImpl.findById()方法调用的是UserDao的方法,反射可不会为对象成员的初始化,但是工具类里定义了成员,所以不会空指针异常

    @Test
    public void test_hello() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        UserService userService = (UserService) Factory.getObject("UserService");
        System.out.println(userService);
        userService.findById(1);
    }

另外知识:
1.反射时注解需要存活到运行期间:@Retention(RetentionPolicy.RUNTIME)

2.char字符串转String方法
String str=new String (char[]c);

3.String转char方法
char []c=c.toCharArray();

4.反射给类的成员对象(Field)初始化

UserService userService= (UserService) Factory.getObject("UserService");
       Class<?> clazz = Class.forName("com.alibaba.service.impl.UserServiceImpl");
       Field field = clazz.getField("userDao");
       field.set(userService,Factory.getObject("UserDao"));

5.遍历map的方法
for (Map.Entry<String, Object> entry : containerMap.entrySet()) {
entry.getKey();
entry.getValue();
}

6.静态代码块最先执行,静态代码块能调用静态方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值