java中的代理设计模式
1、场景:
不需要调用者关注入参是如何变化的,只需要知道在什么情况下使用哪个实现类就可以。所以设计了代理模式,代理本来的接口,实现一个接口根据代理对象的不同,获取不同的时间参数,查询数据。
2、涉及类:
HandlerBeanDefinitionRegistry :Bean注册管理器
CpHistoryProxyFactoryBean:代理bean,入口类
CpHistoryProxyBeanFactory :Bean工厂 , 通过反射new代理对象
CompareHistoryProxyHandler :代理类 ,具体的代理逻辑
3、具体代码
3.1 HandlerBeanDefinitionRegistry
package com.jd.crm.board.proxy;
import com.jd.crm.board.service.HistoryDispatcherService;
import com.jd.crm.board.service.RealDispatcherService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* 容器注册代理bean
*项目启动就初始化 HandlerBeanDefinitionRegistry ,实现代理bean的注册
*
*/
@Component
public class HandlerBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry)
throws BeansException {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(HistoryDispatcherService.class);
GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
definition.setBeanClass(CpHistoryProxyFactoryBean.class);
definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
beanDefinitionRegistry.registerBeanDefinition("historyCompareDispatcherService", definition);
BeanDefinitionBuilder yoybuilder = BeanDefinitionBuilder.genericBeanDefinition(HistoryDispatcherService.class);
GenericBeanDefinition yoyDefinition = (GenericBeanDefinition) yoybuilder.getRawBeanDefinition();
yoyDefinition.setBeanClass(YoyHistoryProxyFactoryBean.class);
yoyDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
beanDefinitionRegistry.registerBeanDefinition("historyYoyDispatcherService", yoyDefinition);
BeanDefinitionBuilder wowbuilder = BeanDefinitionBuilder.genericBeanDefinition(HistoryDispatcherService.class);
GenericBeanDefinition wowDefinition = (GenericBeanDefinition) wowbuilder.getRawBeanDefinition();
wowDefinition.setBeanClass(WowHistoryProxyFactoryBean.class);
wowDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
beanDefinitionRegistry.registerBeanDefinition("historyWowDispatcherService", wowDefinition);
BeanDefinitionBuilder dodbuilder = BeanDefinitionBuilder.genericBeanDefinition(RealDispatcherService.class);
GenericBeanDefinition dodDefinition = (GenericBeanDefinition) dodbuilder.getRawBeanDefinition();
dodDefinition.setBeanClass(DodHistoryProxyFactoryBean.class);
dodDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
beanDefinitionRegistry.registerBeanDefinition("historyDodDispatcherService", dodDefinition);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
3.2 CpHistoryProxyFactoryBean
package com.jd.crm.board.proxy;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import com.jd.crm.board.service.HistoryDispatcherService;
@Slf4j
@Data
public class CpHistoryProxyFactoryBean implements FactoryBean<HistoryDispatcherService>, ApplicationContextAware {
@Override
public HistoryDispatcherService getObject() throws Exception {
Object object = CpHistoryProxyBeanFactory.newMapperProxy();
return (HistoryDispatcherService) object;
}
@Override
public Class<?> getObjectType() {
return HistoryDispatcherService.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
CpHistoryProxyBeanFactory.setApplicationContext(applicationContext);
}
}
3.3 CpHistoryProxyBeanFactory
package com.jd.crm.board.proxy;
import java.lang.reflect.Proxy;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import com.jd.crm.board.service.HistoryDispatcherService;
@Component
public class CpHistoryProxyBeanFactory{
private static ApplicationContext applicationContext;
public static <T> T newMapperProxy() {
CompareHistoryProxyHandler handler = new CompareHistoryProxyHandler(applicationContext);
return (T) Proxy.newProxyInstance(HistoryDispatcherService.class.getClassLoader(), new Class[]{HistoryDispatcherService.class}, handler);
}
public static void setApplicationContext(ApplicationContext arg0)
throws BeansException {
applicationContext = arg0;
}
}
3.4 CompareHistoryProxyHandler
package com.jd.crm.board.proxy;
import com.jd.crm.board.common.CompareDateType;
import com.jd.crm.board.dao.BaseQuery;
import com.jd.crm.board.service.HistoryDispatcherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContext;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 代理逻辑
* 对比逻辑:日期转化为上一个大促的日期 格式不包含时分秒,dao层获取全天累计数据
* @author lvshoawei3
*
*/
@Slf4j
public class CompareHistoryProxyHandler implements InvocationHandler{
private HistoryDispatcherService subject;
private ApplicationContext applicationContext;
CompareHistoryProxyHandler(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
init();
String date = null;
if(args[0] instanceof String){
date = (String)args[0];
}
if (args[0] instanceof BaseQuery){
date = ((BaseQuery) args[0]).getDate();
}
String cpDate = CompareDatestrategy.mapDate(date, CompareDateType.getCompareDateByDate(date));
// log.info("===========cp date before:{}, date mapped:{}", date, cpDate);
if(args[0] instanceof String){
args[0] = cpDate;
}
if (args[0] instanceof BaseQuery){
//这里不要直接改变原来的Query对象里的值
BaseQuery copyQ = new BaseQuery();
BeanUtils.copyProperties(args[0], copyQ);
copyQ.setDate(cpDate);
args[0] = copyQ;
}
return method.invoke(subject, args);
}
private void init() {
if(subject == null) {
HistoryDispatcherService historyDispatcherService = (HistoryDispatcherService)applicationContext.getBean("historyDispatcherServiceImpl");
//HistoryDispatcherService historyDispatcherService = (HistoryDispatcherService)applicationContext.getBean(HistoryDispatcherService.class);
this.subject = historyDispatcherService;
}
}
}