Lookup方法之处理遗留代码

“Lookup方法”可以使Spring替换一个bean原有的,获取其它对象具体的方法,并自动返回在容器中的查找结果。
其实,Lookup方法的工作机制是在不修改原系统代码的情况下,可以轻易的换成别的类型相容的对象而不会影响原系统。Spring是使用CGLIB在字节码级别动态实现出Bean的子类,并重写指定方法的方式来实现这个神奇的功能的。
这个是CGLIG动态生成的类,而不是原来的Bean的实例。所以请记住在任何时候只要定义了一个Bean的Lookup方法,那么这个Bean的实例将是一个CGLIB动态生成的实例而不是原来类的实例。

原文地址:http://blog.csdn.net/qking93415981/archive/2007/08/10/1735617.aspx
UserDao.java

package com.modellite.spring;

public class UserDao
{
private String name;

public UserDao(String name)
{
super();
this.name = name;
}

public UserDao()
{
// TODO Auto-generated constructor stub
}

public void setName(String name)
{
this.name = name;
}
public void create(){
System.out.println("create users from -"+name);
}
}



UserManager.java
在这段代码中UserManager依靠getUserDao方法来获取UserDao对象。由于在getUserDao方法里显示的声明了如何去实例一个UserDao,所以上面的代码不符合IoC模式的风格。虽然使用GetUserDao封装了UserDao的创建过程,但是UserManager和UserDao的关系仍然非常紧密。

package com.modellite.spring;

public class UserManager
{
public UserDao getUserDao()
{
return new UserDao("UserManager.getUserDao()");
}

public void createUser()
{
UserDao dao = getUserDao(); // 通过getUserDao获得userDao
dao.create();
}
}

配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="userManager" class="com.modellite.spring.UserManager">
<lookup-method name="getUserDao" bean="userDao" />
</bean>
<bean id="userDao" class="com.modellite.spring.UserDao">
<constructor-arg>
<value>lookup method</value>
</constructor-arg>
</bean>
</beans>


测试类

ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
UserManager manager=(UserManager) ctx.getBean("userManager");
System.out.println(manager.toString()); //打印userManager的信息
manager.createUser();

Spring还允许Lookup方法中定义的方法带有参数,但是Sping不会处理这些参数。
修改UserManager:

package com.modellite.spring;

public class UserManager
{
public UserDao getUserDao(String daoName){
{
return new UserDao("UserManager.getUserDao()");
}

public void createUser()
{
UserDao dao = getUserDao(); // 通过getUserDao获得userDao
dao.create();
}
}

虽然方法上由参数,但是上面的代码可以正常工作。Spring不会处理这些参数。

Spring对Lookup方法也存在一些限制:
方法不能是private的,但可以是protected的。
方法不能是静态的。
在抽象类和接口上应用Lookup方法有一个比较有趣的用法,就是在抽象类上定义Lookup方法。你一定记得经典的工厂模式吧。定义一个抽象工厂,然后为每一类具体产品实现一个具体产品的工厂。
一个抽象工厂:

package com.modellite.spring;
public abstract class Factory{
public abstract UserDao getProduct();
}

具体一类产品的工厂:

package com.modellite.spring;
public class UserDaoFactory extends Factory{
public UserDao getProduct(){
return new UserDao("UserDaoFactory");
}
}



用户可以通过:
new UserDaoFactory().getProduce();
来获取具体的UserDao产品。
但是如果有很多产品就需要做出实现出很多工厂如,DocumentDaoFactory、GroupDaoFactory等等,这样系统中会出现大量的工厂。工厂的泛滥并不能说明系统的设计是合理的。
既然Spring可以在抽象类上使用Lookup方法,那么我们就可以不同实现真的去实现那么多的子类了。我们可以在抽象类上直接定义Lookup方法和目标对象。用户直接通过抽象类来获得需要的产品对象。看下面这个例子:
Factory.java

package com.modellite.spring;
public abstract class Factory {
public abstract Object getProduct();
}

配置文件添加

<!--如果指定userDaoFactory的类为一个抽象类,并且再这个bean里定义了Lookup方法,那么Spring会自动生成这个抽象类的子类实现。 -->
<bean name="userDaoFactory" class="com.modellite.spring.Factory" scope="prototype">
<lookup-method name="getProduct" bean="userDao" />
</bean>

UserDao并没有改变,我们通过抽象的Factory获得了具体的UserDao的实例。这样即使系统中很多的具体产品我们也不需要实现每类产品的工厂类了。只需要在系统中配置多个抽象工厂,并且配置每个工厂的singlton为false,在用户使用时使用不同抽象工厂的实例就可以了。

<bean name="userDaoFactory" class="com.modellite.spring.Factory" scope="prototype">
<lookup-method name="getProduct" bean="userDao" />
</bean>
<bean name="documentDaoFactory" class="com.modellite.spring.Factory" scope="prototype">
<lookup-method name="getProduct" bean="documentDao" />
</bean>

Spring不关心抽象类中的定义的lookup方法是否时抽象的,Spring都会重写这个方法。

既然Sping可以动态实现抽象类的子类那么,它能不能动态创建出实现一个接口的类呢。答案时肯定的。上面的例子可以直接把Factory变成一个接口,仍然可以正常工作。
这里需要注意的是,只要在一个Bean上明确的定义了Lookup方法,Spring才会使用CGLIB来做原对象的字节码代理。如果一个没有定义Lookup方法的抽象类或接口是不能直接被Spring实例的。

本文介绍了Lookup方法的使用和工作原理,希望读者能够对Lookup方法有了比较深入的了解。虽然我的例子可以简化工厂模式,但是我并不鼓励大家在实际系统中这样做。因为我始终认为“工厂模式”只要在遗留系统中才会碰到。使用IoC模式基本上可以替代所有的对象创建模式。本章的例子只是为了说明Lookup方法如何使用,和Lookup方法的一些特殊情况。Lookup方法一般只在处理遗留代码时使用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值