一、前言
这一节基于前面两节mybatis 中Mapper注入spring源码分析与mybatis 接口依赖注入源码分析的理论,手动实现将接口放入Spring
工厂中,并且能够依赖注入。
二、实践
这里先把已写好的类贴出来,下面会一一介绍。这篇文章的两个目的如下。
目的一:将
TestInterface
接口放入Spring
的工厂中.
@Component
public interface TestInterface {
void test();
}
目的二:当依赖注入成功后,执行test()
方法的时候能够打印一段话:调用test方法成功。
@Autowired
public void test(TestInterface testInterface) {
testInterface.test();
}
2.1 接口放入Spring中
我们可以参考mybatis
中的ClassPathMapperScanner
类的实现,ClassPathMapperScanner
就可以将接口放入Spring
中。默认的ClassPathBeanDefinitionScanner
只能将非抽象类放入Spring
中,接口是不能放入的,因此为了满足接口能放入Spring
中,我们需要重写ClassPathBeanDefinitionScanner
。具体的类如下。
public class TestScanner extends ClassPathBeanDefinitionScanner {
public TestScanner(BeanDefinitionRegistry registry) {
super(registry);
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitions) {
GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();
// 构造函数的入参 这里的BeanClassName 其实就是接口的className
genericBeanDefinition.
getConstructorArgumentValues().
addGenericArgumentValue(genericBeanDefinition.getBeanClassName());
//供spring实例化代理对象使用
genericBeanDefinition.setBeanClass(TestFactoryBean.class);
}
return beanDefinitions;
}
/**
*
* @param beanDefinition
* @return beanDefinition 是接口 && 独立的类,则返回true
*/
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
}
2.2 代理类
2.2.1 TestFactoryBean
这个类就是模仿mybatis
的MapperFactoryBean
,主要作用是能够让Spring
实例化代理对象。
public class TestFactoryBean<T> implements FactoryBean<T> {
private Class<T> testClass;
/**
*
* @param tClass TestInterface 接口class
*/
public TestFactoryBean(Class<T> tClass) {
this.testClass = tClass;
}
/**
* 这个方法将会在依赖注入之前调用。
* @return
* @throws Exception
*/
@Override
public T getObject() throws Exception {
return (T) Proxy.newProxyInstance(testClass.getClassLoader(), new Class[]{testClass}, new TestProxy());
}
@Override
public Class<?> getObjectType() {
return testClass;
}
@Override
public boolean isSingleton() {
return true;
}
}
2.2.2 java 动态代理
这个类参考MapperProxy
.
public class TestProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// getDeclaringClass method 方法在哪个类class中
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
System.out.println("调用"+method.getName()+"方法成功");
// 执行sql 操作。
return "";
}
}
2.3 配置类
@Configuration
public class Config {
@Autowired
public void init(DefaultListableBeanFactory factory) throws Exception {
TestScanner testScanner = new TestScanner(factory);
// 指定扫描哪个包下的class
testScanner.doScan("com.mytijian.order.test");
}
@Autowired
public void test(TestInterface testInterface) {
testInterface.test();
}
}
三、结果
四、总结
其实这三篇文章关键的点还是ClassPathBeanDefinitionScanner
类、Java动态代理、FactoryBean ,只要抓住这三个点就可以了,代码的实现倒是其次,就好像你写一个字我写一个字,字形虽不同但意思却是一样的。