谈谈你对IOC和DI的理解?

IOC 控制翻转,是一种设计理念,由第三方来管理与控制对象。
通常我们创建对象时都是通过new
关键字来实现的。这就带来一些问题。
-
1,每次我们需要使用 对象时,都要手动创建。
-
2,当我们需要对某一个类进行修改时,需要手动将所有通过new 关键字创建的对象,从新编写。工作量将会非常恐怖。
@WebServlet(name = "LoginServlet", urlPatterns = "/check_login")
public class LoginServlet extends HttpServlet {
private IUserService userService = new UserService();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
......省略若干.....
}
}
or
@RestController
public class UserController extends ApiController {
@Resource
private IUserService userService;
@PostMapping("/login")
public Object login(@Valid @RequestBody(required = false) UserReq userReq, HttpSession session) {
......省略若干.....
}
}
如只负责与数据库的数据进行交互DAO层也是如此

public class UserService {
private UserDao userDao = new UserDao();
private RbacDao rbacDao = new RbacDao();
or
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
解决办法就是使用“对象容器”,动态生成JavaBean 对象。通过使用“容器”(applicationContext)我们可以程序中有效的依赖实现“解耦”(降低耦合接触耦合)。
控制翻转--传统情况下我们使用“new”关键字创建对象,也就是由我们编译的程序代码决定使用哪个对象,我们称之为“正向控制”。而“控制反转”则是将对象的控制权交个第三方的“对象容器”,由“对象容器”在运行时创建对应的对象,再赋值给对应的变量。
IOC--最大的优点就是,让 对象 和 对象之间的引用 实现了有效的解耦。因为是在运行时完成的,所以当我们系统底层的类发生变化的时候,只需要修改配置文件就可以了。(极大的方便了工程维护和代码管理)
这里的“对象容器”(applicationContext)我们通常称之为,“IOC”容器。
说说DI是如何在运行时动态注入对象的?
在运行时实例化userDAO类

DI--依赖注入,是IOC控制翻转理念的具体技术实现,由对象容器在运行时动态注入对象。
DI-依赖注入是基于两种技术来实现的。
1,反射--在运行时,进行动态的创建、设置以及管理。
2,工厂模式
说说Java反射吧?
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。
反射的应用场景
在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架,也是利用CGLIB 反射机制才得以实现,下面就举例最常见的两个例子,来说明反射机制的强大之处:
JDBC 的数据库的连接
在JDBC 的操作中,如果要想进行数据库的连接,则必须按照以上的几步完成
- 通过Class.forName()加载数据库的驱动程序 (通过反射加载,前提是引入相关了Jar包)
- 通过 DriverManager 类进行数据库的连接,连接的时候要输入数据库的连接地址、用户名、密码
- 通过Connection 接口接收连接
public class ConnectionJDBC {
/**
* @param args
*/
//驱动程序就是之前在classpath中配置的JDBC的驱动程序的JAR 包中
public static final String DBDRIVER = "com.mysql.jdbc.Driver";
//连接地址是由各个数据库生产商单独提供的,所以需要单独记住
public static final String DBURL = "jdbc:mysql://localhost:3306/test";
//连接数据库的用户名
public static final String DBUSER = "root";
//连接数据库的密码
public static final String DBPASS = "NewPassword";
public static void main(String[] args) throws Exception {
Connection con = null; //表示数据库的连接对象
Class.forName(DBDRIVER); //1、使用CLASS 类加载驱动程序 ,反射机制的体现
con = DriverManager.getConnection(DBURL,DBUSER,DBPASS); //2、连接数据库
System.out.println(con);
con.close(); // 3、关闭数据库
}
国际化i18n的项目
定义I18N接口
public interface I18N {
String say();
}
网站先对中文支持
//中文语言支持类
public class Zhcn implements I18N{
@Override
public String say() {
return "生命不息 奋斗不止!";
}
}
添加配置文件
language=top.xiongmingcai.i18n.Zhcn
读取配置文件
public class Application {
public static void start() {
Properties properties = new Properties();
String name = "/config.properties";
String configPath = Application.class.getResource(name).getPath();
try {
String decode = URLDecoder.decode(configPath, "UTF-8");
properties.load(new FileInputStream(decode));
String language = properties.getProperty("language");
System.out.println("language = " + language);//language = top.xiongmingcai.i18n.Zhcn
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Application.start();
}
}
采用ServletContext读取,读取配置文件的realpath,然后通过文件流读取出来 · MingCaiXiong/java-reflection-learn@c205891
反射调用
I18N i18N = (I18N)Class.forName(language).newInstance();
String say = i18N.say();
System.out.println("say = " + say);
扩展功能
//中文语言支持类
public class En implements I18N {
@Override
public String say() {
return "Cease to struggle and you cease to live.";
}
}
language=top.xiongmingcai.i18n.En
之所以反射在运行下实例化那个类,所有对我们程序留下更多扩展空间,就拿上面例子来说
Class.forName(language).newInstance()
java是不知道实例化那个对象的,因为包含具体类的这个内容他是存放在配置文件中
i18n.En只有当启动以后他才决定实例化那个类,基于这种特性未来增加德文,法文对原始程序不需要任何调整
在线上运行源代码不需要做如何调整,只需在额外添加实现,只需要把对应I18N接口实现,产生*.class 上传服务器,再调整一下对应文件,我们的应用程序就支持对应的语言支持
相关代码