Mybatis基本原理及整合Spring
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
MyBatis 以及与Spring的整合过程中需要解决以下问题
- xml文件中的sql语句如何与接口映射
- mapper接口如何进行实例化
- 如何将mapper对象交给到spring ioc中进行管理
在这片文章中,我们先解决后两个问题,当然我们也应该先大体了解一下第一个问题是如何解决的,其问题的解决与第二个问题息息相关。其实不难解决:
- 首先通过一个读入流将配置xml文件读入,然后交给一个类去解析成一个一个相关配置,最后将解析结果存入到一个对象中(有几个比较重要属性:数据源相关配置,mapper相关位置)
- 在解析过程中,mapper的解析十分重要,mybatis会为将每个mapper接口存入到配置中
- 同时mapper接口和对应的mappersqlxml文件是在同一个路径下的,因此我们只需将配置sql语句的sql解析并存起来,因为sql配置中每个sql语句都具有一个id属性与接口方法名字相对应,因此当执行接口中的方法时,再拿对应的sql语句出来交给特定的执行器进行处理
- 创建一个工厂类根据配置中的创建一个操作类,这个类在Mybatis中称为SqlSession
- mapper接口如何进行实例化?
通过动态代理实现
- 如何将mapper对象交给到spring ioc中进行管理
将动态代理生成的代理对象注册到ioc中,但是我们常用的注册方法通常是现成的一个类,而代理对象是我们动态生成的,没有确定的一个类,这又怎么解决呢?这就不得不提到一个spring中特殊的bean----> factoryBean,其使用的泛型,每个factorybean都对应着一个对象,我们可以通过实现factorybean接口,将我们动态生成的对象返回就可以了
一、重要接口
1.1. BeanDefinitionRegistryPostProcessor
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/*
1. BeanFactoryPostProcessor:提供给开发者一个接口,在调用此接口时 项目中所有的bean都已经被加载,但是未实例化,在此接口中我们可以获取指定的beanDefinition,对其进行修改或者添加属性值
2. BeanDefinitionRegistryPostProcessor继承BeanFactoryPostProcessor,提供了一个注册接口,我们可以通过此接口加载注册我们自己的bean
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
1.2. ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar和BeanDefinitionRegistryPostProcessor功能上相似的
ImportBeanDefinitionRegistrar同样可以注册新的bean,但是其是**@Import注册配套使用的**,他除了提供BeanDefinitionRegistry对象之外,还提供了AnnotationMetadata对象
AnnotationMetadata:继承ClassMetadata, AnnotatedTypeMetadata两个接口,因此其存储了类的元信息和类上注解的信息
ImportBeanDefinitionRegistrar侧重于根据@Import修饰的类的信息和类上其他注解的信息来 注册相关的bean
public interface ImportBeanDefinitionRegistrar {
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
1.3. FactoryBean
//factoryBean.getObject()返回的对象实际上已经完成了实例化和初始化,只是想利用ioc的自动注入等其他功能
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
//继承FactoryBean实现getObject方法,返回我们创建的对象即可将其放入到ioc中管理
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
二、Mapper代理类生成逻辑
因为mapper接口及相关sql语句是在之前被解析出来了,因此需要一个类来维护这些mapper接口,这个类就是MapperRegistry
存在一个mapper生成工厂创建指定的生产对象,这个工厂是MapperProxyFactory。采用工厂方法模式
基于接口实现动态代理,采用了jdk动态代理,需要一个类实现InvocationHandler接口,这个类是MapperProxy
2.1. MapperRegistry
从字面意思上看他是一个mapper的注册中心,其主要保存 mapper接口与代理工厂的关系
mapperRegistry是保存在了Configuration类中,Configuration类就是我们之前从xml文件中解析出来的配置,另外他还根据业务需要提供了一些方法工具类
public class MapperRegistry {
private final Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
public MapperRegistry(Configuration config) {
this.config = config;
}
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);//从已经注册的mapper中获取指定的代理工厂
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {//通过代理工厂创建 mapper接口的代理实例
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
//***省略addMapper等方法
}
2.2. MapperProxyFactory
//工厂方法模式,将生成具体产品的任务分发给具体的产品工厂
//此处主要是基于jdk动态代理 创建对象
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;//要生成的mapper类(也就是接口)
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);//jdk动态代理 生成代理对象
}
public T newInstance(SqlSession sqlSession) {
//创建代理类MapperProxy其实现了InvocationHandler接口
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
//省略getter setter。。。。
}
2.3. MapperProxy
public class MapperProxy<T> implements InvocationHandler, Serializable {
//省略。。。。。
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//具体的与sql绑定并执行
}
//省略。。。。。
}
三、spring整合mybatis
- 将动态生成的代理类交给spring管理->MapperFactoryBean(实现了FactoryBean接口)
- 在spring启动过程中根据配置扫描指定的mapper并创建生成mapperFactoryBean
3.1. MapperFactoryBean
//将对应的MapperFactoryBean放入spring中,spring将会调用getObject方法将返回的实例放入spirng ioc中管理
//继承自SqlSessionDaoSupport其增加了对sqlSession的支持
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
private boolean addToConfig = true;//是否将扫描到的mapperInterface注册到configuration中
public MapperFactoryBean() {}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
//调用了sqlSession中的getmapper方法
//调用链:sqlSession.getMapper()->configuration.getmapper()->mapperRegistry.getmapper->mapperProxyFactory.newInstance()[jdk动态代理生成]
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
//本类继承自SqlSessionDaoSupport,而SqlSessionDaoSupport又继承自DaoSupport
/**
DaoSupport是一个抽象类,实现了InitializingBean接口,我们可能对DaoSuppport不熟悉,但是对JDBCDaoSupport熟悉,JDBCDaoSupport同样是一个抽象类,继承自DaoSupport,在非Mybatis项目中,我们可能会在dao实现了继承JDBCDaoSupport,通过xml配置的形式将datasouce注入到此类中,从而可以使用JDBCDaoSupport中的jdbcTemplate
**/
@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 {
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();
}
}
}
/**
* 省略。。。。
*/
}
3.2. MapperScannerConfigurer
两个问题:
- 有了MapperFactoryBean,我们难道要一个一个的像这样注入
<bean id="xxxxMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="xxxxxMapper"/> </bean>
当我们的mapper多的时候我们该如何自动将其装配呢
答:通过实现BeanDefinitionRegistryPostProcessor接口中的方法,通过扫描指定路径下的mapper接口,并创建相对应的beanDefinition,并将其注册到ioc中
这样我们就可以只将这个实现了BeanDefinitionRegistryPostProcessor接口的类注入就可以了。这个类就是MapperScannerConfigurer。我们可以这样配置:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <property name="basePackage" value="com.lmt.mapper"/> </bean>
**实现:**MapperScannerConfigurer会借助spring中的bean扫描器ClassPathBeanDefinitionScanner,根据 相关配置比如basePackage扫描出相关mapper接口,并创建相关的FactoryBean实例
//实现了BeanDefinitionRegistryPostProcessor,spring将会在所有的bean已经被注册之后而没有实例化之前进行调用ioc中实现了BeanDefinitionRegistryPostProcessor接口的相关方法
public class MapperScannerConfigurer
implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
private String basePackage;
private boolean addToConfig = true;
private String lazyInitialization;
private SqlSessionFactory sqlSessionFactory;
private SqlSessionTemplate sqlSessionTemplate;
private String sqlSessionFactoryBeanName;
private String sqlSessionTemplateBeanName;
private Class<? extends Annotation> annotationClass;
private Class<?> markerInterface;
private Class<? extends MapperFactoryBean> mapperFactoryBeanClass;
private ApplicationContext applicationContext;
private String beanName;
private boolean processPropertyPlaceHolders;
private BeanNameGenerator nameGenerator;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) { //是否对本类 具有占位符的属性进行处理比如Value(${})这种
processPropertyPlaceHolders();
}
//创建类路径下的mapper扫描器,ClassPathMapperScanner继承自ClassPathBeanDefinitionScanner
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
//事实上下面这些信息在执行的时候因为没有配置都是null的【可能是因为有些还没有在spring中初始化化无法注入】,这就会使得ClassPathMapperScanner创建的BeanDefinition没有对应的类的属性值,直接导致创建的MapperFactoryBean没有sqlSession等属性值,影响数据库的操作。那怎么办呢,
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
if (StringUtils.hasText(lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
}
scanner.registerFilters();//设置scanner的扫描策略
scanner.scan(
StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
//此方法中获取了容器中所有的PropertyResourceConfigurer,因为在执行本方法postProcessBeanDefinitionRegistry的时候,还未执行此方法中获取了容器中所有的PropertyResourceConfigurer类中BeanFactoryPostProcessor接口定义的方法,也就无法对【所有的BeanDefintion中的 bean的相关属性值进行设置,所提模拟了一个Spring工厂环境,并将本类注册到其中,最后执行PropertyResourceConfigurer的postProcessBeanFactory方法,从而获取相关属性的值
private void processPropertyPlaceHolders() {
//获取spring中的PropertyResourceConfigurer对象
Map<String, PropertyResourceConfigurer> prcs = applicationContext.getBeansOfType(PropertyResourceConfigurer.class,false, false);
if (!prcs.isEmpty() && applicationContext instanceof ConfigurableApplicationContext){
//获取本类对应的BeanDefinition
BeanDefinition mapperScannerBean = ((ConfigurableApplicationContext) applicationContext).getBeanFactory()
.getBeanDefinition(beanName);
//模拟一个新的factory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition(beanName, mapperScannerBean);//注册本类的beanDefintion
//执行PropertyResourceConfigurer的postProcessBeanFactory接口方法
for (PropertyResourceConfigurer prc : prcs.values()) {
prc.postProcessBeanFactory(factory);//PropertyResourceConfigurer会获取环境中的值并将相关属性放入到本类的BeanDefintion中
}
//获取属性值
PropertyValues values = mapperScannerBean.getPropertyValues();
//依次更新属性信息
this.basePackage = updatePropertyValue("basePackage", values);
this.sqlSessionFactoryBeanName = updatePropertyValue("sqlSessionFactoryBeanName", values);
this.sqlSessionTemplateBeanName = updatePropertyValue("sqlSessionTemplateBeanName", values);
this.lazyInitialization = updatePropertyValue("lazyInitialization", values);
}
this.basePackage = Optional.ofNullable(this.basePackage).map(getEnvironment()::resolvePlaceholders).orElse(null);
this.sqlSessionFactoryBeanName = Optional.ofNullable(this.sqlSessionFactoryBeanName)
.map(getEnvironment()::resolvePlaceholders).orElse(null);
this.sqlSessionTemplateBeanName = Optional.ofNullable(this.sqlSessionTemplateBeanName)
.map(getEnvironment()::resolvePlaceholders).orElse(null);
this.lazyInitialization = Optional.ofNullable(this.lazyInitialization).map(getEnvironment()::resolvePlaceholders)
.orElse(null);
}
//省略。。。。。
}
ClassPathMapperScanner类比较庞大我们只关注其扫描后的处理部分
//ClassPathMapperScanner继承自ClassPathBeanDefinitionScanner,ClassPathBeanDefinitionScanner会根据配置扫描出类并将其封装成BeanDefinition,最后注册到spring中,最后将所有的BeanDefinition交给子类也就是ClassPathMapperScanner处理,下面就是处理方法
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
//遍历
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
//将definition的bean类设置为MapperFactoryBean,也就是 spring中FactoryBean以实现动态生成代理类
definition.setBeanClass(this.mapperFactoryBeanClass);
//--------------------------------------------------------------------------
/*设置 FactoryBean的属性初始值 addToConfig、sqlSessionFactory、sqlSessionTemplate,此时存在两种情况:
1. 这些属性信息可能都不在本类(ClassPathMapperScanner)中存在的,原因是此时这些类还没在spring中实例化,那么就无法设置MapperFactoryBean的初始值.
2.这些对象已经在spring中初始化,MapperScannerConfigurer在初始化的时候可能已经被注入了这些属性信息,将其交给此类也就是ClassPathMapperScanner就可以了,并且在此处可以将MapperFactoryBean的值初始化成功。
那第一种情况下,Spring创建的对象MapperFactoryBean没有SqlSession对象,将直接影响数据库的操作,怎么办呢?看下面:将注入方式设置为类型注入
*/
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;//是否已经初始化的标志
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory",
new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
definition.getPropertyValues().add("sqlSessionTemplate",
new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
//----------------------------------------------------------------------------------
if (!explicitFactoryUsed) {
//如果无法获取FactoryBean所需属性的值,则可以将BeanDefinition设置为根据属性类型进行注入,这就表示在FactoryBean在实例化的时候会根据类型进行注入
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
definition.setLazyInit(lazyInitialization);
}
}
四、spring整合Mybatis对注解@MapperScan的支持
我们已经有了MapperScannerConfigurer类帮助我们扫描并注册相关的类,但是我们仍需要在配置文件中配置MapperScannerConfigurer作为spring的bean,那是否有其他方式简化此步骤呢?答案当然有:@MapperScan
4.1. @MapperScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)//重点
@Repeatable(MapperScans.class)
public @interface MapperScan {
String[] value() default {};
String[] basePackages() default {};
/**
* 省略
*/
}
当spring在启动过程中扫描到标注到配置类上的@MapperScan的注解时(实际上是ConfigurationClassPostProcessor类进行的扫描),发现其内存在@Import注解,则会将import注解导入的类进行处理。
4.2. MapperScannerRegistrar
MapperScannerRegistrar继承自ImportBeanDefinitionRegistrar
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//获取MapperScan注解所标注类上注解的属性值
AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
//根据属性值 beanDefinition
registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
generateBaseBeanName(importingClassMetadata, 0));
}
}
void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
BeanDefinitionRegistry registry, String beanName) {
//建造者模式 创建一个builder,目标defintion为MapperScannerConfigurer
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
//从注解中获取属性值并添加到添加beanDefintiotn对应的属性中--------------------------
builder.addPropertyValue("processPropertyPlaceHolders", true);
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
builder.addPropertyValue("annotationClass", annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
builder.addPropertyValue("markerInterface", markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
}
String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
if (StringUtils.hasText(sqlSessionTemplateRef)) {
builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
}
String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
if (StringUtils.hasText(sqlSessionFactoryRef)) {
builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
}
//basePackage信息
List<String> basePackages = new ArrayList<>();
basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
.collect(Collectors.toList()));
basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
.collect(Collectors.toList()));
if (basePackages.isEmpty()) {
basePackages.add(getDefaultBasePackage(annoMeta));
}
String lazyInitialization = annoAttrs.getString("lazyInitialization");
if (StringUtils.hasText(lazyInitialization)) {
builder.addPropertyValue("lazyInitialization", lazyInitialization);
}
builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
//-------------------------------------------------------------------
//注册此beanDefintion spring最终会将注册的beanDefintion实例化
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
/**
* 省略
*/
}
这是一种常见的注解化模式
五、模仿
自定义一个基于FactoryBean的基于接口自动生成代理对象的组件
5.1. LMTProxy
/**
* @author Li Mengtong
* @time 2021/8/8 10:52
* @Description 代理对象
*/
public class LMTProxy<T> implements InvocationHandler {
private Class<T> lmtInterface;
public LMTProxy(Class<T> lmtInterface) {
this.lmtInterface = lmtInterface;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
System.out.println("\n-------------------------------------------------");
System.out.println("调用" + lmtInterface.getName() + " : " + method.getName() + "方法");
System.out.println("参数为:");
if (args != null)
Arrays.stream(args).forEach(System.out::println);
Class<?> returnType = method.getReturnType();
System.out.println("返回类型:" + returnType.getName());
System.out.println("-------------------------------------------------\n");
if (method.getName().equals("getName")) {
return "你好";
}
return null;
}
}
}
5.2. LMTFactory
代理对象建造工厂
public class LMTFactory<T> {
private Class<T> lmtInterface;
public LMTFactory(Class<T> lmtInterface) {
this.lmtInterface = lmtInterface;
}
public T newInstance() {
final LMTProxy<T> lmtProxy = new LMTProxy<>(lmtInterface);
return (T) Proxy.newProxyInstance(lmtInterface.getClassLoader(), new Class[]{lmtInterface}, lmtProxy);
}
public Class<T> getLmtInterface() {
return lmtInterface;
}
public void setLmtInterface(Class<T> lmtInterface) {
this.lmtInterface = lmtInterface;
}
}
5.3. LMTFactoryBean
基于FactoryBean,实现工厂方法模式下将对象注册至ioc的方法
public class LMTFactoryBean<T> implements FactoryBean<T> {
private Class<T> lmtInterface;
private LMTSqlExecutor sqlExecutor;//仅仅是为了测试 类型注入功能,没有实际功能
@Override
public T getObject() throws Exception {
LMTFactory<T> lmtFactory = new LMTFactory<>(lmtInterface);
return lmtFactory.newInstance();
}
@Override
public Class<?> getObjectType() {
return lmtInterface;
}
public Class<T> getLmtInterface() {
return lmtInterface;
}
public void setLmtInterface(Class<T> lmtInterface) {
this.lmtInterface = lmtInterface;
}
public LMTSqlExecutor getSqlExecutor() {
return sqlExecutor;
}
public void setSqlExecutor(LMTSqlExecutor sqlExecutor) {
System.out.println("LMTSqlExector is being injected into the LMTFactoryBean");
this.sqlExecutor = sqlExecutor;
}
}
5.4. FtBeanImportConfigurer
用来创建指定的FactoryBean类
public class FtBeanImportConfigurer implements BeanDefinitionRegistryPostProcessor {
public static final String IMPORTINTERFACES_ATTRIBUTE_NAME = "ImportInterfaces";
private Class<?>[] ImportInterfaces;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (ImportInterfaces != null) {
for (Class inf : ImportInterfaces) {
if (inf.isInterface()) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(LMTFactoryBean.class);
beanDefinition.getPropertyValues().addPropertyValue("lmtInterface", inf);
beanDefinition.setLazyInit(false);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);//重点:设置为AUTOWIRE_BY_TYPE模式,Spring可以对FactoryBean的属性类型进行分析,并可将可注入的属性进行注入
registry.registerBeanDefinition(inf.getName(), beanDefinition);
} else {
System.out.println("-------- " + inf.getName() + "is not a interface -------------");
}
}
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
public Class<?>[] getImportInterfaces() {
return ImportInterfaces;
}
public void setImportInterfaces(Class<?>[] importInterfaces) {
ImportInterfaces = importInterfaces;
}
}
5.5. 注解化
有了以上几点,我们模仿mybatis建立了一个自己的基于jdk动态代理生成代理对象的小demo,我们可以继续模仿@MapperScan进行注解化配置
5.5.1. FtBeanImportRegister
public class FtBeanImportRegister implements ImportBeanDefinitionRegistrar {//实现ImportBeanDefinitionRegistrar以实现指定类的注册
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//获取注解信息
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnableLmt.class.getName());
Class<?>[] interfaces = null;
for (String key : annotationAttributes.keySet()) {
if (key.equals("value")) {
Object o = annotationAttributes.get(key);
if (o instanceof Class[]) {
interfaces = (Class<?>[]) o;
}
}
}
if (interfaces == null) {
return;
}
// 注册FtBeanImportConfigurer的defintion
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(FtBeanImportConfigurer.class);
beanDefinition.getPropertyValues().add(FtBeanImportConfigurer.IMPORTINTERFACES_ATTRIBUTE_NAME, interfaces);
registry.registerBeanDefinition(beanDefinition.getBeanClassName(), beanDefinition);
}
}
5.5.2. EnableLmt
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FtBeanImportRegister.class)//导入FtBeanImportRegister
public @interface EnableLmt {
Class<?>[] value();//需要导入的接口
}