Java反射➕注解,实现简单版本的IOC

利用反射➕注解,实现简单版本的IOC。

1.先来说下简单说下什么是IOC?

IOC是反转控制 (Inversion Of Control)的缩写。
打个比方:
传统的:当我们需要一个对象的时候需要去new一个。
IOC:当我们需要对象时直接从对象工厂里获取就行了。
在打个比方:
传统的:当我们需要买一台适合自己的电脑时,我们需要自己购买零件,然后组装。
IOC: 我们直接去工厂拿,然后他直接给你一个已经装好的电脑给你。

2.利用反射➕注解自己实现简单版本的IOC

2.1实现之前先来看个图说个问题?

图中的private IUserDao userDao=new IUserDaoImpl();这句代码如果说在实现类比较少的情况下,还是没有太大问题,但是如果说有几百个、上千个实现类呢?那是不是就需要去new 这么多个IUserDaoImpl,但是我们只是需要去用这个IUserDaoImpl里的方法,所以这个new 100个跟new 1个的效果是一样的。
所以这个时候,就出来了一种思想,就是把这个IUserDaoImpl、UserServiceImpl提前放进容器,什么使用什么时候拿出来就行。
在这里插入图片描述

2.2下面请看三种不同的写法。

2.2.1第一种需要哪个类直接去添加哪个

在启动类里需要用哪个就添加哪个
在这里插入图片描述
这是bean工厂
在这里插入图片描述

2.2.2先在配置文件里把需要的类先配置好

  • 添加配置文件
    在这里插入图片描述

改一下bean工厂里的初始化容器的代码
在这里插入图片描述
在启动类里重新测试一下
在这里插入图片描述

2.2.3 直接扫描包把带@Bean注解的类,注入到工厂里去,然后使用@AutoWired注解在需要时使用。

第一步、需要先自定义定义两个注解@Bean、@AutoWired这两个注解干嘛用的呢,一个是代表这个类的是一个bean会在程序运行的后被加载到内存里面,在我们需要使用的时候可以使用@AutoWired拿出来用而不用我们自己去new了。如下代码所示:

package reflects.demo.Annotation;


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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}

package reflects.demo.Annotation;


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

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {
}

第二步、需要改变第二种的写法就是用一个递归去遍历项目编译后的所有class文件。然后把扫出来的路径的前缀清掉留下来一个reflects.demo.Annotation.Bean这样的,当我们有了全类名了,那这个类的所有东西我们都能通过反射拿到,但是在new出对象后是需要我们去装配的不然,这个对象是空的。如下代码所示:

package reflects.demo.reflect;

import reflects.demo.Annotation.AutoWired;
import reflects.demo.Annotation.Bean;
import reflects.demo.dao.IUserDao;
import reflects.demo.dao.Impl.IUserDaoImpl;
import reflects.demo.service.Impl.UserServiceImpl;
import reflects.demo.service.IUserService;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class ApplicationContext<T> {

    //这个是一个存的容器起名叫bean工厂
    private HashMap<Class, Object> beanFactory = new HashMap<Class, Object>();
    private  String filePath;

    //这个是你new 好了之后拿的一个bean
    public T getBean(Class cla) {
        return (T) beanFactory.get(cla);
    }

    //这是通过直接添加的方式,需要什么添加什么
//    public void initContext(){
//        beanFactory.put(IUserDao.class,new IUserDaoImpl());
//        beanFactory.put(IUserService.class,new UserServiceImpl());
//    }


    //这是通过配置文件的方式
    public void initContext() {
        InputStream resource = ApplicationContext.class.getClassLoader()
                .getResourceAsStream("config/bean.config");
        Properties properties = new Properties();
        try {
            properties.load(resource);
            Set<Object> keys = properties.keySet();
            for (Object key : keys) {
                beanFactory.put(Class.forName(key.toString()),
                        Class.forName(properties.getProperty(key.toString())).newInstance());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }




    //加载全部的类的实例
    public  void initContextByAnnotation() {
        filePath = ApplicationContext.class.getClassLoader().getResource("").getFile();
        loadOne(new File(filePath));
        assembleObject();
        System.out.println(filePath);
    }


//这一步是装配的过程就是你new好对象之后,需要把对应的属性给她装配上,不然是个空是没有用的
    private void assembleObject(){
    //遍历工厂拿到每一个对象
        for (Map.Entry<Class,Object> entry : beanFactory.entrySet()){
            Object obj = entry.getValue();
            Class<?> aClass = obj.getClass();
            //遍历每一个对象的属性
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields){
            //这个是判断这个字段上有没有这么一个AutoWired注解,我才给你注入,不然不注入
                AutoWired anntation= field.getAnnotation(AutoWired.class);
                if (anntation !=null){这个
                //因为是暴力注入所以需要
                    field. setAccessible(true);
                    try {
                    //1.给这个属性设置值
                    //2.field.getType()获取这个属性的类型,他就是个Class,也就在bean工厂里的key,然后beanFactory.get(field.getType())就是取出对应的对象,给这个属性赋值。
                        field.set(obj,beanFactory.get(field.getType()));
                    }catch (IllegalAccessException e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     加载一个文件夹的类@param fiLeParent
     */
    private  void loadOne(File fileParent) {
        if (fileParent.isDirectory()) {
            File[] childrenFiles = fileParent.listFiles();
            if (childrenFiles == null || childrenFiles.length == 0) {
                return;
            }
            for (File child : childrenFiles) {
                if (child.isDirectory()) {
                    //如果是个文件夹就继续调用该方法
                    loadOne(child);
                } else {
                    //通过文件路径转变成全类名,第一步把绝对路径部分去掉
                    String pathWithClass = child.getAbsolutePath().substring(filePath.length() - 1);
                    //迭中c1ass文件
                    if (pathWithClass.contains(".c1ass")) {
                        //去掉.class后缀,并且把\替换成.
                        String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
                        try {
                        //这个上面的操作就是遍历每一个文件夹然后取出文件,然后到这里就是通过反射拿到这个类
                            Class<?> aClass = Class.forName(fullName);
                            //把非接口的类实例化放在map中,这里是判断他不是一个接口就new,是的化就不new因为接口不能实列化
                            if (!aClass.isInterface()) {
                                Bean annotation= aClass.getAnnotation(Bean.class);
                                if(annotation !=null){
                                //这里就是利用反射new对象
                                //这里写不好,因为抽象类什么的都没考虑
                                    Object instance = aClass.newInstance();
                                    if(aClass.getInterfaces().length > 0){
                                    //如果有接口,才把他的key当作它的接口
                                        beanFactory.put(aClass.getInterfaces()[0], instance);
                                    }else {
                                    //如果没接口,直接用自己的类存放实例
                                        beanFactory.put(aClass, instance);
                                    }
                                }
                            }
                        } catch (ClassNotFoundException | IllegalAccessException |
                                InstantiationException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

}

第三步、启动类里开始启动

package reflects;

import reflects.demo.dao.IUserDao;
import reflects.demo.dao.Impl.IUserDaoImpl;
import reflects.demo.reflect.ApplicationContext;
import reflects.demo.service.IUserService;

public class BootStrap {
    public static void main(String[] args) {



//        ApplicationContext applicationContext = new ApplicationContext();
//        applicationContext.initContext();
//        System.out.println(applicationContext.getBean(IUserDao.class));


//        ApplicationContext applicationContext = new ApplicationContext();
//        applicationContext.initContextByAnnotation();
//        Object bean= applicationContext.getBean(IUserService.class);
//        System.out.println(bean);

        ApplicationContext applicationContext = new ApplicationContext();
        //初始化容器
        applicationContext.initContextByAnnotation();
        //取出对象
        IUserService userService=(IUserService) applicationContext.getBean(IUserService.class);
        userService.login("sss");

    }
}

下面补全剩余代码:

UserServiceImpl:

package reflects.demo.service.Impl;

import org.springframework.beans.factory.annotation.Autowired;
import reflects.demo.Annotation.AutoWired;
import reflects.demo.Annotation.Bean;
import reflects.demo.dao.IUserDao;
import reflects.demo.dao.Impl.IUserDaoImpl;
import reflects.demo.service.IUserService;

@Bean
public class UserServiceImpl implements IUserService {


//    private IUserDao userDao=new IUserDaoImpl();


    @AutoWired
    private IUserDao userDao;

    public void login(String name) {
        userDao.findByName(name);
        System.out.println("用户登陆了");
    }
}

IUserService

package reflects.demo.service;


import reflects.demo.Annotation.Bean;


public interface IUserService {

    void login(String name);

}

User类的

package reflects.demo.entity;

import java.io.Serializable;

public class User implements Serializable {

    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

IUserDao

package reflects.demo.dao;

import reflects.demo.Annotation.Bean;
import reflects.demo.entity.User;



public interface IUserDao {

    User findByName(String name);

}

IUserDaoImpl

package reflects.demo.dao.Impl;

import reflects.demo.Annotation.Bean;
import reflects.demo.dao.IUserDao;
import reflects.demo.entity.User;

@Bean
public class IUserDaoImpl implements IUserDao {
    public User findByName(String name) {
        System.out.println("用户"+name+"登陆了");
        return null;
    }
}

项目目录结构:
在这里插入图片描述

总结:最后使用的时候自己的路径要注意一下,这个就是一个简单版本的IOC,可以打成一个包然后在另一个项目里直接使用,这里我就不展示了。
总结2:反射跟注解搭配在一起用才是真的绝配,本人学艺不精不喜勿喷。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值