以下面的代码为例
@Mapper //使用了mybatis
@Repository //当出现异常时, 统一使用spring封装的异常
@CacheConfig(cacheNames = "city") //使用了缓存
public interface CityRepository extends BaseMapper<City> { //使用了mybatis-plush
@Cacheable(key = "#id",unless = "#result == null ")
default City findById(String id){
return selectById(id);
}
default City myFind(String id){
//嵌套调用, 此时findById上的注解不会生效.
return findById(id);
}
}
@Configuration
public class TestApplication{
@Autowired
CityRepository cityRepository ;
}
上例中, 给接口CityRepository添加了一堆的注解, 从而实现了一堆的功能, 我好奇spring boot是怎么实现的.
配置spring-boot为debug模式
配置pom.xml
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.version}</version>
<configuration>
<mainClass>com.xx.Application</mainClass>
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
</jvmArguments>
</configuration>
</plugin>
然后在idea中配置一个remote
JDK的动态代理
JDK动态代理示例
public class Main {
private final static Logger log = LogManager.getLogger(Main.class);
public static interface MyInterface{
void run();
}
public static class MyInvoker<T> implements InvocationHandler, Serializable{
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
log.info("invoke");
return null;
}
}
public static void main(String[] args) {
log.info("main");
MyInvoker<MyInterface> invoker = new MyInvoker<MyInterface>();
MyInterface iface = (MyInterface) Proxy.newProxyInstance(Main.class.getClassLoader(),
new Class[]{MyInterface.class}, invoker );
iface.run();
}
}
上面的代码中, 声明了一个接口MyInterface
, 但是并没有定义一个继承它的class, 而是通过java8中的Proxy
动态的创建了一个对象,这个对象可以直接强转为MyInterface
.
spring boot也是采用类似的方式
mybatis-plus怎样处理@Mapper?
将mybatis-plus加到依赖中, spring boot配置会执行MybatisPlusAutoConfiguration
, 通过ClassPathMapperScanner
来扫描包含相关注解的接口
MapperScan.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class) //通过它来扫描带有@Mapper的注解
@Repeatable(MapperScans.class)
public @interface MapperScan {
...
}
MapperScannerRegistrar.java
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
/** 扫描到的带有@Mapper的interface的集合 */
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
//配置sql相关的参数, 读者自己去看代码
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
Mapper相关的Bean工厂MapperFactoryBean
MapperFactoryBean.java
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
//处理interface上定义的各种SQL
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
}
spring-boot对mapper bean的处理
当构造出bean之后, spring boot会bean再做一次处理.
AbstractAutowireCapableBeanFactory.java
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
本文中CityRepository
例子中, 使用了Cacheable
, Repository
, 这两个注解分别对应着两个Processor, 应用到代理中
AbstractAdvisingBeanPostProcessor.java
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}
AbstractAutowireCapableBeanFactory.java
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
最终生成的bean, 是一条很复杂的代理JdkDynamicAopProxy
, 需要进行process的方法存放在它的AdvisedSupport advised
成员中.
比如查找数据后, 需要将结果缓存到cache中, 会调用CacheInterceptor