提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
设计模式-代理模式
一、代理模式的作用?
-
代理模式主要是为了方便调用者访问某些资源,使对象类更加易用,屏蔽底层某些复杂的处理逻辑。
-
以下主要通过代理模式实现模拟Mybatis中对自定义注解的操作,实现自定义的FactoryBean。
二、应用场景?
- 某些中间件,比如RPC框架中,当调用接口时,实际就是通过代理类发出socket进行网络请求;
- MyBatis中,使用代理类实现对Xml或自定义注解里的sql语句执行对应增删改查操作。
三、使用步骤
1.dao层
代码如下(示例):
/**
* @author: kerry
* @date: 2021-09-25 15:31
**/
public interface IUserDao {
@Select("select * from user where id = %s ")
String queryByUserId(long userId);
}
2.自定义注解@Query
代码如下(示例):
/**
* @author: kerry
* @date: 2021-09-25 15:32
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Query {
/**
* 填写sql语句
*
* @return
*/
String value() default "";
}
3.自定义FactoryBean中使用jdk获取代理类
代码如下(示例):
/**
* @program: design-learning
* @desshcription: 自定义factoryBean
* 实现对IUserDao的代理
* @author: kerry
* @date: 2021-09-25 15:35
**/
public class MapperFactoryBean<T> implements FactoryBean<T> {
private Class<T> mapperInterface;
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
@Override
public T getObject() throws Exception {
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Query query = method.getAnnotation(Query.class);
System.out.println(String.format("sql语句:%s,",query.value().replace("%s",args[0].toString()) ));
return args[0]+"查询结果";
}
};
return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),
new Class[]{mapperInterface},
invocationHandler);
}
@Override
public Class<?> getObjectType() {
return mapperInterface;
}
@Override
public boolean isSingleton() {
return true;
}
}
4.注册自定义FactoryBean
代码如下(示例):
/**
* @program: design-learning
* @description: 自定义bean工厂
* 将自定义的FactoryBean注册到beanDefinitionRegistry中,交给spring管理
* @author: kerry
* @date: 2021-09-25 15:43
**/
public class RegisterBeanFactory implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
//设置对应到代理类
beanDefinition.setBeanClass(MapperFactoryBean.class);
beanDefinition.setScope("singleton");
//往构造函数中添加参数
beanDefinition.getConstructorArgumentValues()
.addGenericArgumentValue(IUserDao.class);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, "userDao");
//注册beanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, beanDefinitionRegistry);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
5. spring-context.xml配置文件中注册RegisterBeanFactory
代码如下(示例):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.kerry.design05.proxy.RegisterBeanFactory"></bean>
</beans>
6. 测试
代码如下(示例):
/**
* @program: design-learning
* @description:
* @author: kerry
* @date: 2021-09-25 15:52
**/
public class TestUserDao {
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-context.xml");
IUserDao useDao = beanFactory.getBean("userDao", IUserDao.class);
String result = useDao.queryByUserId(1000L);
System.out.println(result);
}
}