解耦:java
耦合包括:類之間的和方法之間的spring
javabean(用java語言編寫的可重用組件)>實體類shell
在類中直接new的方法,耦合性太過於高,那麼不如將這件事情交給一個工廠類來解決。編程
如下,咱們將爲全部的Bean建立一個工廠類,BeanFactory。app
/** * Bean:可重用組件 */ public class BeanFactory { private static Properties props; //靜態代碼塊 static{ try { //1.實例化Properties對象 props=new Properties(); //2.獲取Properties文件的流對象 InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); props.load(in); } catch (Exception e){ throw new ExceptionInInitializerError("初始化properties失敗"); } } }
BeanFactory初始化時,將從配置文件bean.properties中,獲取Properties元素。框架
接下來實現getBean方法,根據Properties方法獲取組件路徑,並建立對象。函數
/** * 根據bean的名稱獲取bean對象 * @param beanName * @return */ public static Object getBean(String beanName){ Object bean = null; try { String beanPath = props.getProperty(beanName); bean = Class.forName(beanPath).newInstance(); }catch (Exception e){ e.printStackTrace(); } return bean; }
之後就可使用BeanFactory的類方法進行對象建立。測試
// IAccountDao accountDao=new AccountDaoImpl(); IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao");
而後有一個問題是:每次調用getBean方法,咱們都會建立一個BeanFactory對象,這裏徹底能夠替換成單例模式。code
在BeanFactory中定義一個Map容器,存放咱們須要建立的對象xml
private static Map<String,Object> beans;
接下來這樣修改就能獲得單例效果。
/** * Bean:可重用組件 */ public class BeanFactory { private static Properties props; //容器 private static Map<String,Object> beans; //靜態代碼塊 static{ try { //1.實例化Properties對象 props=new Properties(); //2.獲取Properties文件的流對象 InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); props.load(in); //3.容器實例化 beans = new HashMap<String, Object>(); //4.從配置文件中取出全部的key Enumeration<String> keys = (Enumeration)props.keys(); //5.遍歷枚舉 while(keys.hasMoreElements()){ //取出每一個key String key = keys.nextElement(); //根據key獲取value String beanPath = props.getProperty(key); Object value = Class.forName(beanPath); //存放容器 beans.put(key,value); } } catch (Exception e){ throw new ExceptionInInitializerError("初始化properties失敗"); } } /** * 根據bean的名稱獲取bean對象 * @param beanName * @return */ // public static Object getBean(String beanName){ // Object bean = null; // // try { // String beanPath = props.getProperty(beanName); // bean = Class.forName(beanPath).newInstance(); // }catch (Exception e){ // e.printStackTrace(); // } // // return bean; // } public static Object getBean(String beanName){ return beans.get(beanName); } }
// IAccountService accountService=new AccountServiceImpl(); IAccountService accountService = (IAccountService) BeanFactory.getBean("accountService");
這兩行代碼的區別很能體現出IOC的思想。
區別:
以上是咱們本身實現的IOC,這一切若是使用Spring的話,它將幫咱們解決,因此咱們學會了IOC的原理,接下來學Spring的用法。
刪除掉上面的BeanFactory,這個由Spring來作。
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency>
引入約束:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>
建立bean:(bean標籤的tag 」id「寫bean的名字,」class「寫bean的全限定類名)
<bean id="accountDao" class="com.mmj.dao.impl.AccountDaoImpl"></bean> <bean id="accoutService" class="com.mmj.service.impl.AccountServiceImpl"></bean>
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
note:要用Spring的5.0.2版本,其餘版本代碼不太同樣。
public class Client { /** * 獲取Spring的ioc。根據id獲取對象 * @param args */ public static void main(String[] args) { // IAccountService accountService=new AccountServiceImpl(); //1. 獲取核心容器對象 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); IAccountService accountService = (IAccountService) context.getBean("accountService"); System.out.println(accountService); IAccountService accountService2 = (IAccountService) context.getBean("accountService"); System.out.println(accountService2); //accountService.saveAccount(); } }
輸出結果
com.mmj.service.impl.AccountServiceImpl@58134517 com.mmj.service.impl.AccountServiceImpl@58134517
但Spring的容器ApplicationContext和BeanFactory有一些不一樣。
public static void main(String[] args) { //// IAccountService accountService=new AccountServiceImpl(); // //1. 獲取核心容器對象 // ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); // IAccountService accountService = (IAccountService) context.getBean("accountService"); // System.out.println(accountService); // IAccountService accountService2 = (IAccountService) context.getBean("accountService"); // System.out.println(accountService2); // //accountService.saveAccount(); Resource resource = new ClassPathResource("beans.xml"); BeanFactory beanFactory = new XmlBeanFactory(resource); IAccountService accountService = (IAccountService) beanFactory.getBean("accountService"); System.out.println(accountService); } }
這二者的區別在於:
所以:ApplicationContext適用於單例模式(更多),BeanFactory適用於多例模式。
<!--第一種方式,使用組件默認構造函數建立,若是沒有默認構造函數就會報錯--> <bean id="accountDao" class="com.mmj.dao.impl.AccountDaoImpl"></bean>
<!--第二種方式,使用普通工廠方法建立對象(使用某個類中的方法建立對象,而且存入容器)--> <bean id="beanFactory" class="com.mmj.factory.InstanceFactory"></bean> <bean id="accountDao" factory-bean="beanFactory" factory-method="getDao"></bean>
<!--第三種方式,使用工廠中的靜態方法建立--> <bean id="accountDao" class="com.mmj.factory.StaticFactory" factory-method="getStaticDao"></bean>