首先这里说说我知道的spring提供的扩展点:
干预BeanDefinition的信息
例如:设置作用域为prototype
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
BeanDefinition userDao = configurableListableBeanFactory.getBeanDefinition("userDao");
userDao.setScope("prototype");
}
}
干预bean的生命周期
例如:
@Component
public class testBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization");
/**
* 这里我们就可以返回一个代理的bean了,所以spring是在这里完成代理的。
*/
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization");
return bean;
}
}
这里实现的类就会注册Bean由spring管理,使用的时候加上"$"符号,然后还提供了一个方法getObject可以返回一个对象,也会注册Bean交由spring管理,不需要加上符号。
例如Mybatis里面的SqlSessionFactoryBean就实现了FactoryBean,然后getObject返回sqlSessionFactory对象。可以解决SqlSessionFactoryBean下的一些复杂的配置,不需要我们手动去xml里面进行一个配置。
动态实现将一个类是否交由spring管理,可以使用方法registerBeanDefinition注册BeanDefinition到beanDefinitionmap中。
其他还有一个方法、注解,例如:@PostConstruct(){举个例子,布隆过滤器解决redis缓存穿透问题,提前找到为空的给返回了}、afterPropertiesSet方法、init方法等
Import有三种,这里是一种还有两种,一种是导入自己普通的类,普通的类即被component注释的类,第二种就是用importSelector可以实现动态的去开启某个功能,这个下篇文章讲。
@PostConstruct
public void init(){
System.out.println("init");
}
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
</dependencies>
6.1、UserDao接口、UserDaoImpl 实现类
public interface UserDao {
@Select("select * from student where name = #{name}")
public void query(String name);
}
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
UserDao userDao;
@Override
public void query(String name) {
userDao.query(name);
System.out.println("useDao·····");
}
}
6.2、AppConfig类进行扫描
@Configuration
//Configuration,spring源码里面是个if/else,后4个注解使用add添加进行解析的
@ComponentScan("com.spring")
//@Component
//@Import
//@ImportResource("xxx.xml")
//@EnableAspectJAutoProxy
//@MapperScan("com.spring")
@MyMapperScan("com.spring")
public class Appconfig {
@Bean
@Autowired
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
@Bean
public DataSource dataSource(){
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("123456");
driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/dayi?useUnicode=true&characterEncoding=utf8");
driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
return driverManagerDataSource;
}
}
6.3、自定一个自己的MyMapperScan注解
@Retention(RetentionPolicy.RUNTIME)
@Import(MyImportBeanDefinitionRegistrar.class)
public @interface MyMapperScan {
public String value();
}
6.4、ImportBeanDefinitionRegistrar 的实现类读取bd并且注册bd
注意这里的构造方法添加构造类型beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(“com.spring.dao.UserDao”);,
可以给后续的Factory的实现类中的构造方法动态获取接口
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/***
* 得到bd
*/
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserDao.class);
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();
//设置构造方法接口类型
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("com.spring.dao.UserDao");
//添加beanclass
beanDefinition.setBeanClass(MyFactoryBean.class);
//注册beanDefinition存进map
registry.registerBeanDefinition("userDao",beanDefinition);
}
}
6.5、实现Factory进行注册Bean,返回代理对象
模拟Mapper,使用动态代理,返回代理对象。
public class MyFactoryBean implements FactoryBean {
//构造方法动态获取接口
Class clazz;
public MyFactoryBean(Class clazz) {
this.clazz = clazz;
}
@Override
public Object getObject() throws Exception {
Class[] claszz = new Class[]{clazz};
//动态代理
Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), claszz, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy");
//得到代理对象接口的方法
Method method1 = proxy.getClass().getInterfaces()[0].getMethod(method.getName(),String.class);
//得到select注解信息
Select select = method1.getDeclaredAnnotation(Select.class);
//得到注解信息得value值是个数组
System.out.println(select.value()[0]);
return proxy;
}
});
return o;
}
@Override
public Class<?> getObjectType() {
return clazz;
}
@Override
public boolean isSingleton() {
return false;
}
}
6.6、 最后是我们的启动类
public class Test02 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new
AnnotationConfigApplicationContext(Appconfig.class);
UserDao userDao = (UserDao) annotationConfigApplicationContext.getBean("userDaoImpl");
userDao.query("zhangsan");
}
}
5.7、控制台打印结果如下
返回了代理对象,知道了sql语句。
proxy
select * from student where name = #{name}
useDao·····
对ImportBeanDefinitionRegistrar和Factory的使用有了进一步的了解。