前言
Spring给用户提供了很多干预bean的外部接口,最近就看到了一个比较有趣的接口的ApplicationContextAware。既然说到应用,就要假设一个场景:UserA登陆,要走ServiceA。UserB登陆,要走ServiceB。不同的角色给不同的逻辑处理,比如区分白金用户,一般用户等等。本篇就简单说一下在Spring框架下的实现思路。更多Spring内容进入【Spring解读系列目录】。
ApplicationContextAware
public interface ApplicationContextAware extends Aware {
/**
* Set the ApplicationContext that this object runs in.
* Normally this call will be used to initialize the object.
* <p>Invoked after population of normal bean properties but before an init callback such
* as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
* {@link MessageSourceAware}, if applicable.
* @param applicationContext the ApplicationContext object to be used by this object
* @throws ApplicationContextException in case of context initialization errors
* @throws BeansException if thrown by application context methods
* @see org.springframework.beans.factory.BeanInitializationException
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
上面的代码来自Spring源码。首先先介绍一下这个接口里的唯一方法setApplicationContext()
。从官方描述来看Set the ApplicationContext that this object runs in.
是说,这个方法可以在本对象运行时设置ApplicationContext
。什么意思呢,就是能够拿到运行时的ApplicationContext
,然后根据内容进行设置。直接说肯定比较抽象,下面通过一个例子展示一下它的功能。
Sample
首先假设有一个接口OrderDao
,还有两个类去实现不同的逻辑OrderDaoImplA
和OrderDaoImplB
,还有一个OrderServiceImpl
用来去区分要使用哪一个Dao
去实现具体的逻辑。最终希望,UserA
登陆执行OrderDaoImplA
,UserB
登陆执行OrderDaoImplB
。
public interface OrderDao {
public void logical(String user);
}
@Component
public class OrderDaoImplA implements OrderDao{
public void logical(String user){
System.out.println(user);
}
}
@Component
public class OrderDaoImplB implements OrderDao{
public void logical(String user){
System.out.println(user);
}
}
重点就在于要如何实施OrderServiceImpl
,其实也非常简单。首先要获取到ApplicationContext
,因为拿到这个就能够对Spring实例化后的bean进行区分处理,所以ApplicationContextAware
用法就在这里。
@Service
public class OrderServiceImpl implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void changeOrder(String userName){
//对不同的User进行分类处理,并且根据User拿到对应的bean,执行不同的逻辑
if (userName.equals("UserA")){
((OrderDao)applicationContext.getBean("orderDaoImplA")).logical("UserA move");
}else if (userName.equals("UserB")){
((OrderDao)applicationContext.getBean("orderDaoImplB")).logical("UserB move");
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext; //获取到applicationContext
}
}
public class AOPMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext anno=new AnnotationConfigApplicationContext(AppConfig.class);
OrderServiceImpl orderService=anno.getBean(OrderServiceImpl.class);
orderService.changeOrder("UserA");
//orderService.changeOrder("UserB");
}
}
输出,传入哪个User,就使用哪个逻辑。
UserA move
//UserB move
另一个思路
上面的例子呢,只是为了展示ApplicationContextAware
的使用方法是什么样的,就举出来的例子而言,我们还有一个更加便捷的办法。那就是使用一个Map去交给Spring处理,这个方法对于刚刚假设的场景来说更加的便捷,我们只需要把OrderServiceImpl
改造成下面的样子,同样是可以完成这个效果的。
@Service
public class OrderServiceImpl {
//Spring会自动把所有符合OrderDao接口的实现给实例化到map中
// 也就意味着这个map里存的是
// <(String)orderDaoImplA:(Object)OrderDaoImplA>,
// <(String)orderDaoImplB:(Object)OrderDaoImplB>
Map<String,OrderDao> map;
@Autowired
public void setMap(Map<String, OrderDao> map) {
this.map = map;
}
public void changeOrder(String userName){
//因此我们只要在map中拿到对应的处理类就可以了
if (userName.equals("UserA")){
map.get("orderDaoImplA").logical("UserA move");
}else if (userName.equals("UserB")){
map.get("orderDaoImplB").logical("UserB move");
}
}
}