`
zhangzuanqian
  • 浏览: 270027 次
  • 来自: ...
社区版块
存档分类
最新评论

Spring内核研究-Lookup方法注入

阅读更多

Lookup方法注入

   “Lookup方法”可以使Spring替换一个bean原有的,获取其它对象具体的方法,并自动返回在容器中的查找结果。
我们来看这个例子:
UserDao.java
    在UserDao的构造函数中接受一个name参数,创建UserDao的对象会把自己的名字传递给userDao,这样userDao的create方法中就会把userDao的创建者打印出来。
package research.spring.beanfactory.ch2; public class UserDao { private String name=""; public UserDao(String name){ this.name=name; } public void create(){ System.out.println("create user from - "+name); } }

 

UserManager.java
    在这段代码中UserManager依靠getUserDao方法来获取UserDao对象。由于在getUserDao方法里显示的声明了如何去实例一个UserDao,所以上面的代码不符合IoC模式的风格。虽然使用GetUserDao封装了UserDao的创建过程,但是UserManager和UserDao的关系仍然非常紧密。
package research.spring.beanfactory.ch2; public class UserManager { public UserDao getUserDao() { return new UserDao("UserManager.getUserDao()"); } public void createUser() { UserDao dao = getUserDao(); //通过getUserDao获得userDao dao.create(); } }

 

LookupMethodTest.java
    通过BeanFactory获得UserManager,并调用createUser方法。
package research.spring.beanfactory.ch2; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; public class LookupMethodTest { public static void main(String[] args) { XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource("research/spring/beanfactory/ch2/context.xml")); UserManager manager=(UserManager) factory.getBean("userManager"); manager.createUser(); //create a User } }

context.xml

xml version="1.0" encoding="UTF-8"?> DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> bean> <bean name="userDao class="research.spring.beanfactory.ch2.UserDao" > bean> beans>

    运行LookupMethodTest你会看到屏幕输入” create user from - UserManager.getUserDao()”。

    由于是遗留系统,所以我们不能修改UserManager。现在我希望让这个UserManager依赖的Dao对象由spring管理,而不修改原有的代码。
    在这个场景中我们就可以利用Spring提供的“Lookup方法”来替换原有的getUserDao方法,实现自动获取userDao的功能。修改context.xml:
xml version="1.0" encoding="UTF-8"?> DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> bean> <bean name="userDao" class="research.spring.beanfactory.ch2.UserDao" > <constructor-arg> <value>lookup methodvalue> constructor-arg> bean> <bean name="userDaoFactory" class="research.spring.beanfactory.ch2.UserDaoFactory"> bean> beans>

    再次运行LookupMethodTest你会看到不同的输出结果“create user from - lookup method”。字符串“lookup method”是通过构造函数注入给userDao的。原来的userManager.java并没有作任何修改,仍然是通过UserDao dao = getUserDao();来获得userDao的。这说明Spring已经替换了原有的getUserDao方法的实现,当执行getUserDao时Spring会在容器中寻找指定的Bean,并返回这个Bean。

Lookup方法的工作机制
    通过这种机制我们可以在不修改原系统代码的情况下,可以轻易的把UserDao换成别的类型相容的对象而不会影响原系统。Spring是使用CGLIB在字节码级别动态实现出userManager的子类,并重写getUserDao方法的方式来实现这个神奇的功能的。
修改LookupMethodTest.java:
package research.spring.beanfactory.ch2; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; public class LookupMethodTest { public static void main(String[] args) { XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource( "research/spring/beanfactory/ch2/context.xml")); UserManager manager=(UserManager) factory.getBean("userManager"); System.out.println(manager.toString()); //打印userManager的信息 manager.createUser(); //create a User } }

    我们在获取UserManager的实例后打印出这个实例的信息,再次运行LookupMethodTest你会看到:

 

注意manager.toString()打印出了:
    这个是CGLIG动态生成的类,而不是原来的UserManager的实例。所以请记住在任何时候只要定义了一个Bean的Lookup方法,那么这个Bean的实例将是一个CGLIB动态生成的实例而不是原来类的实例。
 
Spring允许在一个Bean中定义多个Lookup方法。
   
<bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> <lookup-method name="getOtherDao" bean="otherDao" /> bean>

上面的做法是合法的,并且可以正常工作。
 
    虽然Spring会用CGLIB动态生成一个带有Lookup方法bean的子类,但是这并不影响Spring完成其它的功能。Sping还是允许Lookup方法和setXXX、构造函数注入以及后面我们将介绍的自动依赖检查和自动装配的功能同时使用。
 
    Spring还允许Lookup方法中定义的方法带有参数,但是Sping不会处理这些参数。
修改UserManager:
package research.spring.beanfactory.ch2; public class UserManager { private UserDao dao; public void setDao(UserDao dao) { this.dao = dao; } public UserDao getUserDao(String daoName) { return new UserDao("UserManager.getUserDao()"); } public void createUser() { UserDao dao = getUserDao(“userDao”); //通过getUserDao获得userDao dao.create(); } }

 

虽然方法上由参数,但是上面的代码可以正常工作。Spring不会处理这些参数。
 
Spring对Lookup方法也存在一些限制:
  • 方法不能是private的,但可以是protected的。
  • 方法不能是静态的。
在抽象类和接口上应用Lookup方法
    有一个比较有趣的用法,就是在抽象类上定义Lookup方法。你一定记得经典的工厂模式吧。定义一个抽象工厂,然后为每一类具体产品实现一个具体产品的工厂。
一个抽象工厂:
package research.spring.beanfactory.ch2; public abstract class Factory { public abstract UserDao getProduct(); }

 

具体一类产品的工厂:
package research.spring.beanfactory.ch2; public class UserDaoFactory extends Factory{ public UserDao getProduct(){ return new UserDao("UserDaoFactory"); } }

 

用户可以通过:

 

new UserDaoFactory().getProduce();

 

来获取具体的UserDao产品。

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

 

context.xml
    如果指定userDaoFactory的类为一个抽象类,并且再这个bean里定义了Lookup方法,那么Spring会自动生成这个抽象类的子类实现。
xml version="1.0" encoding="UTF-8"?> DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> bean> <bean name="userDao" class="research.spring.beanfactory.ch2.UserDao" > <constructor-arg> <value>lookup methodvalue> constructor-arg> bean> <bean name="userDaoFactory" class="research.spring.beanfactory.ch2.Factory" singleton="false"> <lookup-method name="getProduct" bean="userDao" /> bean> beans>

 

Test.java
package research.spring.beanfactory.ch2; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; public class LookupMethodTest { public static void main(String[] args) { XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource( "research/spring/beanfactory/ch2/context.xml")); //获得抽象工厂 Factory abstractFactory=(Factory) factory.getBean("userDaoFactory"); UserDao userDao=(UserDao) abstractFactory.getProduct(); System.out.println(userDao.toString()); userDao.create(); } }

 

运行Test你会看到:
research.spring.beanfactory.ch2.UserManager$$EnhancerByCGLIB$$cc2f8f1c@12c7568
create user from - lookup method

    对,这个结果和上面的例子是完全一样的。UserDao并没有改变,我们通过抽象的Factory获得了具体的UserDao的实例。这样即使系统中很多的具体产品我们也不需要实现每类产品的工厂类了。只需要在系统中配置多个抽象工厂,并且配置每个工厂的singlton为false,在用户使用时使用不同抽象工厂的实例就可以了。
 
<bean name="userDaoFactory" class="research.spring.beanfactory.ch2.Factory" singleton="false"> <lookup-method name="getProduct" bean="userDao" /> bean> <bean name="documentDaoFactory" class="research.spring.beanfactory.ch2.Factory" singleton="false"> <lookup-method name="getProduct" bean="documentDao" /> bean>

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

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

分享到:
评论

相关推荐

    spring-beans-3.0.xsd

    在`&lt;bean&gt;`元素中,`lookup-method`和`replaced-method`属性的引入,使得在运行时动态查找或替换bean的方法成为可能,这是对AOP(面向切面编程)的一种补充,提供了更细粒度的控制。 除此之外,`&lt;util&gt;`命名空间在...

    ip domain-lookup命令解释

    `ip domain-lookup`命令的使用方法 ##### 2.1 启用DNS查询 要启用DNS查询功能,可以在全局配置模式下使用`ip domain-lookup`命令。这表示设备将在执行某些操作时(例如ping命令)自动进行DNS查询。 ``` 2500...

    Spring-Data-MongoDB3.2

    - 实现Repository接口:创建自定义的Repository接口,继承Spring Data MongoDB提供的基类,并定义所需的查询方法。 **5. 使用示例** 例如,定义一个UserRepository接口: ```java public interface ...

    spring-jdbc-4.2.xsd.zip

    《Spring JDBC 4.2.xsd详解》 在Java企业级开发中,Spring框架是不可或缺的一部分,它提供了全面的编程和配置模型,极大地简化了应用的构建和维护。Spring JDBC作为Spring框架的一部分,主要负责数据库操作,使得...

    rapidsh-SSH经典整合框架-包括权限管理-文件上传下载-用户管理-分页-lookup

    Struts2作为表现层框架,Spring作为应用上下文和依赖注入容器,Hibernate则作为持久层框架,用于数据库操作。这个整合框架提供了强大的功能,如权限管理、文件上传下载、用户管理以及分页查询,是企业级应用开发的...

    spring-jndi-lookup:如何使用Spring从JNDI查找数据源

    如何使用Spring从JNDI查找数据源 Server.xml &lt;资源名称=“ jdbc / javatechie”全局=“ jdbc / javatechie” auth =“容器” type =“ javax.sql.DataSource” driverClassName =“ com.mysql.jdbc.Driver” url...

    深入理解Spring中的Lookup(方法注入)

    在Spring框架中,Lookup方法注入是一种特殊的依赖注入方式,它允许Spring容器动态替换bean中的某个方法,以便在运行时返回不同实例。这种方法主要用于处理单例bean依赖非单例bean的情况,确保每次调用都能获得一个新...

    PyPI 官网下载 | drf-multi-lookup-0.0.14.tar.gz

    标题中的"PyPI 官网下载 | drf-multi-lookup-0.0.14.tar.gz"表明这是一个从Python Package Index (PyPI)官方下载的软件包,名为`drf-multi-lookup`,版本为0.0.14,且以tar.gz格式压缩。这个包可能是针对Python...

    前端开源库-nsq-lookup-jc

    【nsq-lookup-jc】是一个专为前端开发者设计的开源库,主要用于与nsqlookupd服务进行交互,帮助开发者方便地查找并连接到nsqd节点。nsq是一款由Golang编写的高可用、高性能的消息队列系统,常用于实时处理大规模数据...

    PyPI 官网下载 | drf-multi-lookup-0.0.19.tar.gz

    《PyPI上的drf-multi-lookup-0.0.19.tar.gz:Python库与分布式系统集成解析》 在IT领域,Python作为一种强大且灵活的编程语言,被广泛应用于各种项目,尤其是Web开发。PyPI(Python Package Index)是Python开发者...

    devicon-lookup:在每个文件名的开头添加正确的devicon

    用例用例包括:将devicons放在目录中的文件之前ls | devicon-lookup --color向grep结果添加图标rg test | devicon-lookup --prefix :大型结果集的流式结果rg str --color always | devicon-lookup -c -p : | fzf --...

    Linux-vfs-path-lookup

    文件系统原生文档path-lookup翻译

    PyPI 官网下载 | digdeo-syspass-ansible-lookup-0.2.4.tar.gz

    标题中的"PyPI 官网下载 | digdeo-syspass-ansible-lookup-0.2.4.tar.gz"指的是在Python Package Index (PyPI) 官网上可以找到的一个开源项目,名为`digdeo-syspass-ansible-lookup`。这个项目版本号为0.2.4,被打包...

    nested-lookup-feedstock:一个用于嵌套查找的conda-smithy存储库

    通过使用以下方法将conda-forge添加到您的通道中,可以从conda-forge通道安装nested-lookup : conda config --add channels conda-forge 启用conda-forge频道后,可以使用以下命令安装nested-lookup : conda ...

    spring-jee-4.2.xsd.zip

    《Spring框架中的XSD文件详解——以spring-jee-4.2.xsd为例》 在软件开发领域,Spring框架以其强大的功能和灵活的配置而备受推崇。Spring框架的核心在于其XML配置文件,其中包含了对应用组件和服务的定义。在XML...

    springboot 基础简易实例, maven项目

    --------------------------- DemoApplication 运行 main 方法即可启动 springboot --------------------------- package com.example.demo; import org.springframework.boot.SpringApplication; import org....

    iso-countries-lookup:通过多种语言的国家名称查找国家_地区代码

    iso-countries-lookup 使用输入的基本容错能力的多种语言按国家/地区名称查找国家/地区代码(ISO 3166-1 alpha-2)。 返回给定国家/地区名称的ISO 3166-1 alpha-2国家/地区代码。 支持基于以及基于备用名称。 安装...

    spring-jms-4.2.xsd.zip

    标题中的"spring-jms-4.2.xsd.zip"表明这是一个与Spring框架的Java消息服务(JMS)相关的压缩文件,版本为4.2。xsd是XML Schema Document的缩写,用于定义XML文档的结构和数据类型。这个压缩包很可能包含了一个...

    Python库 | digdeo-syspass-ansible-lookup-0.1.1.tar.gz

    资源分类:Python库 所属语言:Python 资源全名:digdeo-syspass-ansible-lookup-0.1.1.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

Global site tag (gtag.js) - Google Analytics