在Java Web项目里实现IOC(不使用框架,自己通过代码实现)

一:IOC的好处
有的项目在管理DAO的时候会抽象出一个interface,如ArticleDao;然后去做一些他的实现:如ArticleDaoForDb2或者ArticleDaoForOracle。这样在Servlet里面new一个ArticleDao可以写成:
ArticleDao articleDao=new ArticleDaoForOracle

这种做法带来的问题:项目一大,就有很多dao类,如ContentDao,PersonDao等等等。如果有一天要将他们的实现从ForOracle改成ForDb2,这样在代码里面的改动就会很大。
IOC:控制翻转,本来需要在代码里面将某个类的具体实现new出来的,现在不用new了,只需要在配置文件做一下配置。这样一来,如果我们想将dao的实现从ForOracle改成ForDb2。只需要在一个配置文件里面改就行了,不用再在很多个的servlet类里面一个个的改。
个人认为IOC适用于一些大项目,对于一些小项目,本身就只有一个实现,就没有必要做这个,因为有了IOC也会增加项目的复杂度。

二:在项目中实现IOC
1.创建一个beans.properties文件,用于存放bean的具体实现:

articleDao=bruce.zhao.cms.backend.dao.impl.ArticleDaoImpl
channelDao=bruce.zhao.cms.backend.dao.impl.ChannelDaoImpl

2.创建一个制造bean的工厂,通过反射来创造写在配置文件里面的那些bean

public class PropertiesBeanFactory implements BeanFactory{

	//该工厂类产生的bean都放在这个map里面
	Map beans=new HashMap();
	//默认的properties文件的名字为:beans.properties
	private String congfigLocation="beans.properties";
	
	public PropertiesBeanFactory(){
		init();
	}
	
	public PropertiesBeanFactory(String configLocation){
		setCongfigLocation(configLocation);
		init();
	}
	
	private void init(){
		try {
			Properties properties=new Properties();
			
			//将properties文件load进来
			properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(congfigLocation));
			//将properties对象转换为一个set,便于遍历
			Set set=properties.entrySet();
			//循环遍历properties文件里面的一条条记录
			for (Iterator iterator=set.iterator(); iterator.hasNext(); ) {
				Map.Entry entry=(Map.Entry)iterator.next();
				String keyString=(String)entry.getKey();
				String className=(String)entry.getValue();
				Class clz=Class.forName(className);
				Object bean= clz.newInstance();
				//将实例化好的类放进map
				beans.put(keyString, bean);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}
	
	public Object getBean(String name){
		return beans.get(name);
	}

	/**
	 * @return the congfigLocation
	 */
	public String getCongfigLocation() {
		return congfigLocation;
	}

	/**
	 * @param congfigLocation the congfigLocation to set
	 */
	public void setCongfigLocation(String congfigLocation) {
		this.congfigLocation = congfigLocation;
	}
}

3.创建一个InitBeanFactoryServlet,该servlet在web.xml里面不需要配置对应的map,因为只有在初始化的时候会用到,但是需要设置启动项为0,让他最先初始化。
<servlet>
    <description></description>
    <display-name>InitBeanFactoryServlet</display-name>
    <servlet-name>InitBeanFactoryServlet</servlet-name>
    <servlet-class>bruce.zhao.cms.backend.view.InitBeanFactoryServlet</servlet-class>
    <init-param>
      <param-name>configLocation</param-name>
      <param-value>beans.properties</param-value>
    </init-param>
    <load-on-startup>0</load-on-startup>
  </servlet>

该类的作用:在容器启动的时候调用PropertiesBeanFactory来产生写在properties配置文件里面的类,把他们放在ServletContext里面。

public class InitBeanFactoryServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	public static final String INIT_FACTORY_NAME="_my_bean_factory";

	/* (non-Javadoc)
	 * @see javax.servlet.GenericServlet#init()
	 */
	@Override
	public void init(ServletConfig config) throws ServletException {
		BeanFactory beanFactory=null;
		String configLocation =config.getInitParameter("configLocation");
		if (configLocation==null) {
			//如果在web.xml里面没有配置properties文件的名字则
			beanFactory=new PropertiesBeanFactory();
		}else {
			beanFactory=new PropertiesBeanFactory(configLocation);
		}
		config.getServletContext().setAttribute(INIT_FACTORY_NAME, beanFactory);
	}

}

4.创建一个BaseServelt,所有别的servlet都继承自他,他的子类会先调用他的service方法,通过反射查看子类里面有没有bean的set方法,如果有就在ServletContext里面获取对应的bean。(第三部的时候,InitBeanFactoryServlet 已经将所有的bean都放到了ServletContext里面)

public class BaseServelt extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		BeanFactory beanFactory=(BeanFactory) getServletContext().getAttribute(InitBeanFactoryServlet.INIT_FACTORY_NAME);
		
		Method[] methods=this.getClass().getMethods();
		for (Method method : methods) {
			if (method.getName().startsWith("set")) {
				String propertyName=method.getName().substring(3);
				StringBuffer sb =new StringBuffer(propertyName);
				sb.replace(0, 1, (propertyName.charAt(0)+"").toLowerCase());
				propertyName=sb.toString();
				Object bean= beanFactory.getBean(propertyName);
				try {
					method.invoke(this, bean);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		
		super.service(request, response);
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值