preface
In the recent development of the financial system, encountered a problem: because the group finance database access control, lead to test and pre-release environment only part of the machine have the access rights to the group’s financial database, and the code does not distinguish between machines, lead to develop test validation because no environment in the process of leading the function block. In line with the principle of not invading business code, try to rely on Spring to solve the problem by directly skipping access to the group’s financial database in a specific environment. Since we need to rely on Spring to solve, then we need to first understand the spring bean and mybatis automatic injection of some basic mechanism, incidentally also for the future to write similar install X code to do some preparation.
1. Lifecycle of spring-bean
2. Mybaitis annotations are automatically scanned for injection
The target program
- Replace myBatis automatically generated classes with proxy classes
- The loading mechanism of Spring itself is not affected
- This parameter takes effect based on the environment configuration
Implementation scheme
Added tag annotations to mark mapper classes that can be proxied
@Retention(RetentionPolicy.RUNTIME)
public @interface MapperMock {
}
Copy the code
Implementation of BeanPostProcessor, when there is an environment variable mapperMock=true, with its own proxy class to replace mapper automatically generated proxy class
@ConditionalOnProperty(name = "mapperMock", havingValue = "true") public class MapperMockBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof MapperFactoryBean) { MapperFactoryBean mapperFactoryBean = (MapperFactoryBean) bean; Class clazz = mapperFactoryBean.getMapperInterface(); MapperMock mock = (MapperMock) clazz.getAnnotation(MapperMock.class); Class[] superClasses = clazz.getInterfaces(); Class[] finalClasses = new Class[superClasses.length + 1]; System.arraycopy(superClasses, 0, finalClasses, 1, superClasses.length); finalClasses[0] = clazz; if (mock == null) { return bean; } else { bean = new FactoryBean() { @Override public Object getObject() throws Exception { return Proxy.newProxyInstance(clazz.getClassLoader(), finalClasses, new InvocationHandler() { @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { Class returnType = method.getReturnType(); if (int.class.equals(returnType)) { return 0; } if (byte.class.equals(returnType)) { return 0; } if (float.class.equals(returnType)) { return 0f; } if (long.class.equals(returnType)) { return 0l; } if (double.class.equals(returnType)) { return 0d; } if (char.class.equals(returnType)) { return 0; } if (boolean.class.equals(returnType)) { return false; } if (short.class.equals(returnType)) { return 0; } return null; }}); } @Override public Class getObjectType() { return clazz; } @Override public boolean isSingleton() { return true; }}; } } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }}Copy the code
If you want to rely on Spring to write a generic code framework 1. By implementing ImportBeanDefinitionRegistrar scan specific note 2. Implement FactoryBean to customize the generated objects. 3. Implement BeanPostProcessor to do special processing for beans
For example, you can write code to simplify configuration like kqueue
Fan Shilong