做一个网站放网上要多少钱,驻马店市做网站,网站常见的风格,长沙快速排名优化一、本文内容分类
1、接口功能 2、接口运用场景 3、使用案例 4、注意事项
二、接口功能介绍
描述#xff1a;ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,它可以支持我们自己写的代码封装成BeanDefinition对象,注册到Spring容器中#xff0c;功能类似于注…一、本文内容分类
1、接口功能 2、接口运用场景 3、使用案例 4、注意事项
二、接口功能介绍
描述ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,它可以支持我们自己写的代码封装成BeanDefinition对象,注册到Spring容器中功能类似于注解Service Component。 很多三方框架集成Spring的时候都会通过该接口实现扫描指定的类然后注册到spring容器中比如Mybatis中的Mapper接口springCloud中的FeignClient接口都是通过该接口实现的自定义注册逻辑。 1、ImportBeanDefinitionRegistrar接口实现类只能通过Import注解的方式来注入通常把Import修饰在启动类或配置类。 2、使用Import如果括号中的类是ImportBeanDefinitionRegistrar的实现类启动时会触发ImportBeanDefinitionRegistrar接口的方法将其中要注册的类注册成bean。 3、实现该接口的类拥有注册bean的能力。 //接口所有抽象方法合并看就一个注册BeanDefinition的方法
public interface ImportBeanDefinitionRegistrar {//把自定义的类封装成BeanDefinition对象注册到Spring里面去default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {registerBeanDefinitions(importingClassMetadata, registry);}//我们平时重写这个就可以了default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {}
}三、接口运用场景
四、使用案例
1、案例1
自定义业务类UserServiceTest通过ImportBeanDefinitionRegistrar将注册Spring容器中。在通过spring容器获取BeanUserServiceTest
//业务类
public class UserServiceTest {/*** 获取用户名称* return 用户名称*/public String getUserName(){return 测试;}
}ImportBeanDefinitionRegistrar实现类
//注意这里不能加注解要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {//业务类转成bd注册到spring容器中注入Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//1、通过Bd工具类生成bd对象只是这个Db对象比较纯洁没有绑定任何类BeanDefinitionBuilder beanDefinitionBuilder BeanDefinitionBuilder.genericBeanDefinition();GenericBeanDefinition beanDefinition (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();//2、设置bd绑定的类型beanDefinition.setBeanClass(UserServiceTest.class);//3、注册到spring容器中registry.registerBeanDefinition(userServiceTest,beanDefinition);}
}Configuration
Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfigClassTest {//在配置类导入ImportBeanDefinitionRegistrar实现类
}//测试
public static void main(String[] args) {AnnotationConfigApplicationContext AnnotationConfigApplicationContext new AnnotationConfigApplicationContext(AppConfigClassTest.class);UserServiceTest userServiceTest AnnotationConfigApplicationContext.getBean(userServiceTest, UserServiceTest.class);String userName userServiceTest.getUserName();System.out.println(userName);
}如果只是把业务类注册到Spring容器中我们通过其他注解就可以了那么ImportBeanDefinitionRegistrar有没有更高级的玩法。
2、案例2
public interface UserServiceTestInterface {public void list();
}//因为是接口但是spring的容器里面是不允许注入接口的只能是接口的实现类。如果我们写个去实现接口那就没有什么意义了没必要搞得那么复杂这次我们通过代理类来完成对接口的实现。public class MyInvocationHandler implements InvocationHandler {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(代理类逻辑代码);return null;}
}//注意这里不能加注解要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//通过工具类生成一个bd只是这个Db对象比较纯洁没有绑定任何类BeanDefinitionBuilder beanDefinitionBuilder BeanDefinitionBuilder.genericBeanDefinition();GenericBeanDefinition beanDefinition (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();//设置Bean的类型MyInvocationHandler类型是实现类的类型不是接口类型。因为在实例化的时候调用的是设置类型所以对应的构造方法。beanDefinition.setBeanClass(MyInvocationHandler.class);//注册到Spring容器中进去registry.registerBeanDefinition(userServiceTest,beanDefinition);}
}//通过配置类导入ImportBeanDefinitionRegistrar的实现类
Configuration
Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfigClassTest {
}测试
public static void main(String[] args) {AnnotationConfigApplicationContext AnnotationConfigApplicationContext new AnnotationConfigApplicationContext(AppConfigClassTest.class);//通过name获取Bean注意此时的bean类型不是UserServiceTestInterface类型而是MyInvocationHandlerObject userServiceTestInterface AnnotationConfigApplicationContext.getBean(userServiceTest);if(userServiceTestInterface instanceof MyInvocationHandler){//代码实际会走到这里把object转成带代理类。MyInvocationHandler u (MyInvocationHandler) userServiceTestInterface;//生成接口UserServiceTestInterface的代理对象UserServiceTestInterface o (UserServiceTestInterface) Proxy.newProxyInstance(MainTest.class.getClassLoader(), new Class[]{UserServiceTestInterface.class}, u);}
}3、案例3
定义一个业务接口通过FactoryBeanInvocationHandler来生成该接口的代理类无需手动写业务接口的实现类很多底层框架就是这样实现的。 InvocationHandler主要是通过Invoke方法来拦截业务接口的方法 FactoryBean主要是用来将生成的代理类。 ImportBeanDefinitionRegistrar在这里的作用就是帮忙我们把自定义的FactoryBean注册到Spring中 //业务接口
public interface UserServiceTestInterface {public void list();
}自定义FactoryBean这样我们控制Bean的创建的过程实现InvocationHandler用来拦截业务接口的方法。
//创建代理类代理UserServiceTestInterface接口UserServiceTestInterface接口方法在执行前后都会被invoke方法拦截
//FactoryBean可以生成某一个类型Bean实例它最大的一个作用是可以让我们自定义Bean的创建过程
public class MyFactoryBean implements FactoryBean, InvocationHandler {//为了使这个类更好地扩展。创建更多的接口我们定义一个参数让他们通过参数传递进来。private Class classs;//添加一个有参的构造方法。public MyFactoryBean(Class classs){this.classs classs;}//拦截Class的所有方法Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(diaoyonlejiekou123);return null;}//返回bean的对象。spring会自动把它add到容器里面去。Overridepublic Object getObject() throws Exception {Class[] clazzs new Class[]{classs};//目标类集合。//通过proxy来得到代理对象。本来最有一个参数需要穿代理类对象但因为本类实现了InvocationHandler所以只需传thisObject proxy Proxy.newProxyInstance(this.getClass().getClassLoader(), clazzs, this);return proxy;//返回的这个对象会把加到spring的容器中。}//返回要添加到容器里bean的类型Overridepublic Class? getObjectType() {return this.classs;}
}自定义ImportBeanDefinitionRegistrar实现类把我们自定义的FactoryBean注册到Spring中。
//注意这里不能加注解要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//通过工具类生成一个bd只是这个Db对象比较纯洁没有绑定任何类BeanDefinitionBuilder beanDefinitionBuilder BeanDefinitionBuilder.genericBeanDefinition();//为什么要转成GenericBeanDefinition这种类型。因为GenericBeanDefinition有更多修改bd属性的方法。后面我会介绍为什么要修改属性。GenericBeanDefinition beanDefinition (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();//这里很重要。getConstructorArgumentValues是为了获取该bd的所有构造方法因为我们重写了有参构造方法所有我们需要带参数过去 //不然spring没法帮我们实例化addGenericArgumentValue是添加参数该代码会执行两步//第一步是匹配对应的构造方法第二步是实例化。beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserServiceTestInterface.class.getName());//因为代理对象类型的实例化的时候走的是代理类的构造方法beanDefinition.setBeanClass(MyFactoryBean.class);//注册bdregistry.registerBeanDefinition(userServiceTest,beanDefinition);}
}测试
public static void main(String[] args) {AnnotationConfigApplicationContext AnnotationConfigApplicationContext new AnnotationConfigApplicationContext(AppConfigClassTest.class);//通过name获取BeanObject userServiceTestInterface AnnotationConfigApplicationContext.getBean(userServiceTest);//针对这种场景Bean的类型是通过FactoryBean的getObjectType方法返回的。UserServiceTestInterface u (UserServiceTestInterface) userServiceTestInterface;u.list();
}