代理模式情景代理模式实战
代理模式情景代理模式用于某些资源的访问, 对象的类 易用操作上提供方便使用的代理服务. 用到的一些组件会提供给你简单易用的方式控制原本需要编写很多代码进行使用的服务类.
例如rpc框架, 在拿到jar包对接口的描述后, 会生成代理类, 当调用接口的时候, 通过代理类发出socket信息进行通信.
mybatis框架, 只写了接口, 框架会在底层生成代理类去执行crud操作.
模拟mybatis 生成代理类.
类图如下
编写自定义注解Select
@documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Select {
String value() default "";
}
定义dao接口
public interface IUserDao {
@Select("select userName from user where id = #{uId}")
String queryUserInfo(String uId);
}
代理类定义MapperFactoryBean
通过继承FactoryBean,提供bean对象,也就是方法;T getObject()。
getObject 中进行反射操作.
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.FactoryBean; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; // 通过继承FactoryBean,提供bean对象,也就是方法;T getObject()。 public class MapperFactoryBeanimplements FactoryBean { private Logger logger = LoggerFactory.getLogger(MapperFactoryBean.class); private Class mapperInterface; // 提供构造函数来透传需要被代理类,Class mapperInterface,在mybatis中也是使用这样的方式进行透传。 public MapperFactoryBean(Class mapperInterface) { this.mapperInterface = mapperInterface; } //在方法 getObject()中提供类的代理以及模拟对sql语句的处理,这里包含了用户调用dao层方法时候的处理逻辑。 @Override public T getObject() { // 通过代理, 把参数进行赋值. InvocationHandler handler = ((proxy, method, args) -> { Select select = method.getAnnotation(Select.class); logger.info("sql : {}", select.value().replace("#{uId}", args[0].toString())); logger.info("args[0] : {}", args[0].toString()); // 此处return的是接口返回的结果, 实际中为数据库查询的结果, 此处写死一个. return "张三"; }); return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{mapperInterface}, handler); } // getObjectType()提供对象类型反馈,以及isSingleton()返回类是单例的。 @Override public Class> getObjectType() { return mapperInterface; } @Override public boolean isSingleton() { return true; } }
将Bean定义注册到Spring容器
import com.thc.design.IUserDao;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
public class RegisterBeanFactory implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 用于定义一个bean的基本信息setBeanClass(MapperFactoryBean.class);,
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
// 将代理的bean交给spring容器管理
beanDefinition.setBeanClass(MapperFactoryBean.class);
beanDefinition.setScope("singleton");
//可以透传给构造函数信息addGenericArgumentValue(IUserDao.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(IUserDao.class);
//BeanDefinitionReaderUtils.registerBeanDefinition,进行bean的注册,也就是注册到DefaultListableBeanFactory
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, "userDao");
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
定义spring-config.xml
测试类
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@Test
public void test_IUserDao() {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
IUserDao userDao = beanFactory.getBean("userDao", IUserDao.class);
String res = userDao.queryUserInfo("100001");
logger.info("测试结果: {}", res);
}
}
运行测试类 , 结果如下
15:40:51.556 [main] INFO c.thc.design.agent.MapperFactoryBean - sql : select userName from user where id = 100001 15:40:51.556 [main] INFO c.thc.design.agent.MapperFactoryBean - args[0] : 100001 15:40:51.556 [main] INFO com.thc.design.ApiTest - 测试结果: 张三



