IOC 核心思想
下面我们用JavaWeb的方式进行引入IOC的核心思想
1.导包
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!--设置 maven jdk版本 默认为5 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
2.编写Servlet
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Spring");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.在pom中修改war打包方式,添加tomcat并运行
<packaging>war</packaging>
4.Servlet、Service、Dao
HelloDao
public interface HelloDao {
List<String> getAll();
}
HelloDaoImpl
public class HelloDaoImpl implements HelloDao {
@Override
public List<String> getAll() {
return Arrays.asList("1","2","3");
}
}
HelloService
public interface HelloService {
List<String> getAll();
}
HelloServiceImpl
public class HelloServiceImpl implements HelloService {
private static HelloDao helloDao = new HelloDaoImpl();
@Override
public List<String> getAll() {
return helloDao.getAll();
}
}
HelloServlet
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
private static HelloService helloService = new HelloServiceImpl();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write(helloService.getAll().toString());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
当需求发生变更时,可能需要频繁修改Java代码,效率很低,如何解决?
使用静态工厂来创建特定的实现类,不再把代码写死到Service中
静态工厂
public class BeanFactory {
public static HelloDao getDao(){
return new HelloDaoImpl();
}
}
private HelloDao helloDao = BeanFactory.getDao();
上述方式并不能解决我们的问题,需求发生改变时,我们虽然无需修改Service,但还要修改BeanFactory中的代码。如何不改Java代码,就可以实现实现类的切换呢?
外部配置文件的方式
将具体的实现类写到配置文件中,Java程序只需要读取配置文件即可。
1.定义外部配置文件
factory.properties
helloDao = com.demo.dao.impl.HelloDaoImpl
2.Java程序读取这个配置文件
public class BeanFactory {
private static Properties properties;
// 实例化properties
static {
properties = new Properties();
try {
//读取配置文件
properties.load(BeanFactory.class.getClassLoader().getResourceAsStream("factory.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object getDao(){
String value = properties.getProperty("helloDao");
System.out.println(value);//com.demo.dao.impl.HelloDaoImpl
// 反射机制创建对象
try {
Class clazz = Class.forName(value);
Object obj = null;
try {
obj = clazz.getConstructor().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return obj;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
3.修改Service
private HelloDao helloDao = (HelloDao) BeanFactory.getDao();
4.测试
Spring IOC 中的bean是单例
此时我们利用工厂创建出来的对象不是单例,我们还需优化 — 缓存
BeanFactory
利用Map
集合创建缓存已经生成的对象,并使用双重检测锁
来维护单例模式。
private static Map<String, Object> cache = new HashMap<>();
public static Object getDao(String beanName) {
// 判断缓存中是否存在Bean
if (!cache.containsKey(beanName)) {
synchronized (BeanFactory.class) {
if (!cache.containsKey(beanName)) {
// 将bean存入缓存
// 反射机制创建对象
try {
String value = properties.getProperty(beanName);//com.demo.dao.impl.HelloDaoImpl
Class clazz = Class.forName(value);
Object obj = clazz.getConstructor().newInstance();
// 存入缓存
cache.put(beanName,obj);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
return cache.get(beanName);
}
总结
1、private HelloDao helloDao = new HelloDaoImpl();
2、private HelloDao helloDao = (HelloDao) BeanFactory.getDao("helloDao");
1、强依赖/紧耦合,编译之后无法修改,没有扩展性;
2、弱依赖/松耦合,编译之后仍然可以修改,让程序具有更好的扩展性。
自己放弃了创建对象的权限,将创建对象的权限交给了BeanFactory,这种将控制权交给别人的思想,就是控制反转IOC。