6.spring系列- 单例bean中的多例bean

先看个案例

实体类ServiceA和ServiceB

public class ServiceA {
}
public class ServiceB {

    private ServiceA serviceA;

    public ServiceA getServiceA() {
        return serviceA;
    }

    public void setServiceA(ServiceA serviceA) {
        this.serviceA = serviceA;
    }
}

xml 配置:
注意:ServiceA配置是多例的,ServiceB默认是单例

	<bean id="serviceA" class="com.spring.lookupMethod.ServiceA" scope="prototype"/>

    <bean id="serviceB" class="com.spring.lookupMethod.ServiceB">
        <property name="serviceA" ref="serviceA"/>
    </bean>

测试:

@Test
    public void lookupMethod() {
        String path = "classpath:/bean/lookupMethod.xml";
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(path);
        Object serviceA1 = context.getBean("serviceA");
        Object serviceA2 = context.getBean("serviceA");
        System.out.println("serviceA --> " + serviceA1);
        System.out.println("serviceA --> " + serviceA2);

        ServiceB serviceB1 = (ServiceB)context.getBean("serviceB");
        ServiceB serviceB2 = (ServiceB)context.getBean("serviceB");
        System.out.println("serviceB --> " + serviceB1);
        System.out.println("serviceB --> " + serviceB2);

        ServiceA serviceA = serviceB1.getServiceA();
        ServiceA serviceA3 = serviceB2.getServiceA();
        System.out.println("serviceB.serviceA --> " + serviceA);
        System.out.println("serviceB.serviceA --> " + serviceA3);
    }

执行结果:

serviceA --> com.spring.lookupMethod.ServiceA@7c137fd5
serviceA --> com.spring.lookupMethod.ServiceA@183ec003
serviceB --> com.spring.lookupMethod.ServiceB@7d9d0818
serviceB --> com.spring.lookupMethod.ServiceB@7d9d0818
serviceB.serviceA --> com.spring.lookupMethod.ServiceA@221a3fa4
serviceB.serviceA --> com.spring.lookupMethod.ServiceA@221a3fa4

结论:

因为ServiceA我们配置的是多例,所以每次从容器中获取的ServiceA都是不一样的。ServiceB是单例的,在ServiceB中的ServiceA也是同一个对象。

如果我们想每次获取ServiceB中的ServiceA都是不一样的,该如何处理。可以使用ApplicationContextAware#setApplicationContext,我们就可以获取applicationContext

修改ServiceB,是它实现ApplicationContextAware接口:

public class ServiceB implements ApplicationContextAware {

    ApplicationContext applicationContext;

    private ServiceA serviceA;

    public ServiceA getServiceA() {
        return applicationContext.getBean(ServiceA.class);
    }

    public void setServiceA(ServiceA serviceA) {
        this.serviceA = serviceA;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

测试方法不变,运行结果如下:

serviceA --> com.spring.lookupMethod.ServiceA@7c137fd5
serviceA --> com.spring.lookupMethod.ServiceA@183ec003
serviceB --> com.spring.lookupMethod.ServiceB@7d9d0818
serviceB --> com.spring.lookupMethod.ServiceB@7d9d0818
serviceB.serviceA --> com.spring.lookupMethod.ServiceA@24569dba
serviceB.serviceA --> com.spring.lookupMethod.ServiceA@5ddeb7cb

这样就可以实现,但是对spring的api有耦合的作用。所以我们使用方法拦截,spring中的lookup-method就可以实现这样的功能。

我们改造ServiceB:

public class ServiceB {

    private ServiceA serviceA;
	
	//直接返回null
    public ServiceA getServiceA() {
        return null;
    }

    public void setServiceA(ServiceA serviceA) {
        this.serviceA = serviceA;
    }

}

xml 改造:

    <bean id="serviceA" class="com.spring.lookupMethod.ServiceA" scope="prototype"/>
	
    <bean id="serviceB" class="com.spring.lookupMethod.ServiceB">
        <lookup-method name="getServiceA" bean="serviceA"/>
    </bean>

测试方法不变,我们运行看结果:

serviceA --> com.spring.lookupMethod.ServiceA@1787f2a0
serviceA --> com.spring.lookupMethod.ServiceA@7de62196
serviceB --> com.spring.lookupMethod.ServiceB$$EnhancerBySpringCGLIB$$2f4980fe@163370c2
serviceB --> com.spring.lookupMethod.ServiceB$$EnhancerBySpringCGLIB$$2f4980fe@163370c2
serviceB.serviceA --> com.spring.lookupMethod.ServiceA@51bf5add
serviceB.serviceA --> com.spring.lookupMethod.ServiceA@7905a0b8

spring还提供了一个功能replaced-method,需要实现MethodReplacer接口

案例:

MyMethodReplacer

public class MyMethodReplacer implements ApplicationContextAware , MethodReplacer {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object reimplement(Object o, Method method, Object[] objects) throws Throwable {
        return this.applicationContext.getBean(ServiceA.class);
    }
}

xml 配置:

<bean id="serviceA" class="com.spring.lookupMethod.ServiceA" scope="prototype"/>

    <bean id="myMethodReplacer" class="com.spring.lookupMethod.MyMethodReplacer"/>


    <bean id="serviceB" class="com.spring.lookupMethod.ServiceB">
    	<!--name 为拦截的方法名 myMethodReplacer:实现MethodReplacer接口的bean名-->
        <replaced-method name="getServiceA" replacer="myMethodReplacer"/>
    </bean>

ServiceB#getServiceA,还是返回null,测试方法不变,运行结果如下:

serviceA --> com.spring.lookupMethod.ServiceA@7905a0b8
serviceA --> com.spring.lookupMethod.ServiceA@35a3d49f
serviceB --> com.spring.lookupMethod.ServiceB$$EnhancerBySpringCGLIB$$2f4980fe@389b0789
serviceB --> com.spring.lookupMethod.ServiceB$$EnhancerBySpringCGLIB$$2f4980fe@389b0789
serviceB.serviceA --> com.spring.lookupMethod.ServiceA@1b410b60
serviceB.serviceA --> com.spring.lookupMethod.ServiceA@2462cb01

总结

lookup-method:方法查找,可以对指定的bean的方法进行拦截,然后从容器中查找指定的bean作为被拦截方法的返回值

replaced-method:方法替换,可以实现bean方法替换的效果,整体来说比lookup-method更灵活一些

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值