手写SpringIoc

  • IoC 控制反转 Inverse of Control 创建对象的权限,Java 程序中需要用到的对象不再由程序员自己创建,而是交给 IoC 容器来创建。
  • 将创建对象的权限交给了BeanFactory,这种将控制权交给别人的思想,就是控制反转 IoC。

pom.xml

<dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>
 </dependencies>

1、使用配置文件进行类加载

Dao层

public interface HelloDao {
    List<String> finaAll();
}
public class HelloDaoImpl01 implements HelloDao {
    @Override
    public List<String> finaAll() {
        return Arrays.asList("1","2","3");
    }
}
public class HelloDaoImpl02 implements HelloDao {
    @Override
    public List<String> finaAll() {
        return Arrays.asList("4","5","6");
    }
}

Service层

public interface HelloService {
    List<String> findAll();
}
/**
 * 耦合,使用静态工厂
 */
public class HelloServiceImpl implements HelloService{
	//传入BeanName
    private HelloDao helloDao= (HelloDao) BeanFactory.getDao("helloDao");

    @Override
    public List<String> findAll() {
        return helloDao.finaAll();
    }
}

Servlet层

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    private HelloService helloService=new HelloServiceImpl();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write(helloService.findAll().toString());
    }
}

定义工厂类BeanFactory


/**
 * 使用配置文件+反射的方法解耦合
 */
public class BeanFactory {

    private static Properties properties;
    private static Map<String,Object> cache=new HashMap<>();


    static {
        properties=new Properties();
        //获取字节流
        try {
            properties.load(BeanFactory.class.getClassLoader().getResourceAsStream("factory.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Object getDao(String beanName){
        //先判断缓存中是否有bean
        if(!cache.containsKey(beanName)){
            //双重检查
            synchronized (BeanFactory.class){
                if(!cache.containsKey(beanName)){
                    try {
                        String value = properties.getProperty(beanName);
                        Class<?> aClass = Class.forName(value);
                        Constructor<?> constructor = aClass.getConstructor();
                        Object object = constructor.newInstance();
                        cache.put(beanName,object);
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }

        }

        return cache.get(beanName);
    }
}

factory.properties

helloDao=com.tan.dao.HelloDaoImpl01
  • 通过修改配置文件,使得ioc容器进行相关类的加载

2、Ioc 基于注解的执行原理

手写SpringIoc_第1张图片
手写代码的思路:

1、自定义一个 MyAnnotationConfigApplicationContext,构造器中传入要扫描的包。

2、获取这个包下的所有类。

3、遍历这些类,找出添加了 @Component 注解的类,获取它的 Class 和对应的 beanName,封装成一个 BeanDefinition,存入集合 Set,这个机会就是 IoC 自动装载的原材料。

4、遍历 Set 集合,通过反射机制创建对象,同时检测属性有没有添加 @Value 注解,如果有还需要给属性赋值,再将这些动态创建的对象以 k-v 的形式存入缓存区。

5、提供 getBean 等方法,通过 beanName 取出对应的 bean 即可

参考:B站楠哥教你学Java

你可能感兴趣的:(Spring,ioc,spring)