首页
留言
Search
1
在Centos7下搭建Socks5代理服务器
1,035 阅读
2
在windows11通过Zip安装Mysql5.7
574 阅读
3
Mysql5.7开放远程登录
482 阅读
4
数据库
469 阅读
5
mysql5.7基本命令
377 阅读
综合
正则表达式
git
系统
centos7
ubuntu
kali
Debian
网络
socks5
wireguard
运维
docker
hadoop
kubernetes
hive
openstack
ElasticSearch
ansible
前端
三剑客
Python
Python3
selenium
Flask
PHP
PHP基础
ThinkPHP
游戏
我的世界
算法
递归
排序
查找
软件
ide
Xshell
vim
PicGo
Typora
云盘
安全
靶场
reverse
Java
JavaSE
Spring
MyBatis
C++
QT
数据库
mysql
登录
Search
标签搜索
java
centos7
linux
centos
html5
JavaScript
php
css3
mysql
spring
mysql5.7
linux全栈
ubuntu
BeanFactory
SpringBean
python
python3
ApplicationContext
kali
mysql8.0
我亏一点
累计撰写
139
篇文章
累计收到
8
条评论
首页
栏目
综合
正则表达式
git
系统
centos7
ubuntu
kali
Debian
网络
socks5
wireguard
运维
docker
hadoop
kubernetes
hive
openstack
ElasticSearch
ansible
前端
三剑客
Python
Python3
selenium
Flask
PHP
PHP基础
ThinkPHP
游戏
我的世界
算法
递归
排序
查找
软件
ide
Xshell
vim
PicGo
Typora
云盘
安全
靶场
reverse
Java
JavaSE
Spring
MyBatis
C++
QT
数据库
mysql
页面
留言
搜索到
14
篇与
Spring
的结果
2023-03-04
Java Spring IoC整体流程总结
Java Spring IoC整体流程总结1. 整体流程2. SpringBean基本实例化过程3. BeanFactory后处理器过程4. Bean生命周期阶段
2023年03月04日
125 阅读
0 评论
0 点赞
2023-03-04
Java Spring 生命周期
Java Spring 生命周期1. 概述Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:Bean的实例化阶段: Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是sinaleton的是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化;Bean的初始化阶段: Bean创建之后还仅仅是个"半成品”,还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,后面要学习的Spring的注解功能等spring高频面试题Bean的循环引用问题都是在这个阶段体现的:Bean的完成阶段: 经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期2. 初始化阶段2.1 Bean的初始化阶段涉及过程Spring Bean的初始化过程涉及如下几个过程Bean实例的属性填充Aware接口属性注入BeanPostProcessor的before()方法回调InitializingBean接口的初始化方法回调自定义初始化方法init回调BeanPostProcessor的after()方法回调2.2 Bean实例属性填充Spring在进行属性注入时,会分为如下几种情况:注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题2.2.1 propertyValuesBeanDefinition 中有对当前Bean实体的注入信息通过属性propertyValues进行了存储PersonDao.javapackage org.example; public interface PersonDao { }UserDao.javapackage org.example; public interface UserDao { }UserDaoImpl.javapackage org.example; public class UserDaoImpl implements UserDao { }PersonDaoImpl.javapackage org.example; public class PersonDaoImpl implements PersonDao{ public String getName() { return name; } public void setName(String name) { this.name = name; } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } private String name; private UserDao userDao; } beans.xml<bean class="org.example.UserDaoImpl" id="userDao"/> <bean class="org.example.PersonDaoImpl" id="personDao"> <property name="userDao" ref="userDao"/> <property name="name" value="名字"/> </bean>主函数调用ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");例如PersonDao的属性信息如下:2.2.2 循环引用多个实体之间相互依赖并形成闭环的情况就叫做”循环依赖”,也叫做”循环引用。死循环原理图UserDaoImpl.javapackage org.example; public class UserDaoImpl implements UserDao { private UserService userService; public UserService getUserService() { return userService; } public void setUserService(UserService userService) { this.userService = userService; } } UserServiceImpl.javapackage org.example; public class UserServiceImpl implements UserService { private UserDao userDao; public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } } beans.xml<bean class="org.example.UserDaoImpl" id="userDao"> <property name="userService" ref="userService"/> </bean> <bean class="org.example.UserServiceImpl" id="userService"> <property name="userDao" ref="userDao"/> </bean>2.2.3 三级缓存解决循环引用问题Spring提供了三级缓存存储完整Bean实例和半成品Bean实例,用于解决循环引用问题在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:UserService和UserDao循环依赖的过程结合上述三级缓存描述一下UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存;UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移入二级缓存:UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存UserService 注入UserDao:UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存2.3 常用的Aware接口Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封装性,我们接触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用不到这些对象,如果用到了就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象。在pom.xml添加ServletContext依赖jar包 <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency>UserServiceImpl.javapackage org.example; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class UserServiceImpl implements UserService, ApplicationContextAware, BeanNameAware, BeanFactoryAware { public UserServiceImpl() { System.out.println("构造方法执行"); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("BeanFactory--------" + beanFactory.toString()); } @Override public void setBeanName(String s) { System.out.println("BeanName--------" + s); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("ApplicationContext--------" + applicationContext.toString()); } } 主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); System.out.println(userService); }执行结果构造方法执行 BeanName--------userService BeanFactory--------org.springframework.beans.factory.support.DefaultListableBeanFactory@319b92f3: defining beans [userDao,userService]; root of factory hierarchy ApplicationContext--------org.springframework.context.support.ClassPathXmlApplicationContext@1a93a7ca, started on Sat Mar 04 15:19:28 CST 2023 org.example.UserServiceImpl@436a4e4b{x}
2023年03月04日
99 阅读
0 评论
0 点赞
2023-03-02
Java Spring Bean工厂后处理器
Java Spring Bean工厂后处理器Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:BeanFactoryPostProcessor: Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;BeanPostProcessor: Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行。1. BeanFactoryPostProcessor1.1 快速入门BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,那么Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。实例化流程MyBeanFactoryPostProcessor.javapackage processor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { System.out.println("beanDefinitionMap填充完毕后回调该方法"); } } beans.xml<bean class="processor.MyBeanFactoryPostProcessor"/>主函数断点调试public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); }执行结果beanDefinitionMap填充完毕后回调该方法1.2 强制修改BeanDefinition其他设置基于上文MyBeanFactoryPostProcessor.javapublic class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { System.out.println("beanDefinitionMap填充完毕后回调该方法"); BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("userService"); beanDefinition.setBeanClassName("org.example.UserDaoImpl"); } }主函数调用public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object userService = applicationContext.getBean("userService"); System.out.println(userService); }输出结果beanDefinitionMap填充完毕后回调该方法 org.example.UserDaoImpl@3c875211.3 动态注入BeanDefinition创建一个新的接口PersonDaopublic interface PersonDao { }创建一个新的类PersonDaoImpl,并且继承PersonDao接口public class PersonDaoImpl implements PersonDao{ }MyBeanFactoryPostProcessor.javapublic class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { System.out.println("beanDefinitionMap填充完毕后回调该方法"); //注册BeanDefinition BeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClassName(PersonDaoImpl.class.getName()); //强转为DefaultListableBeanFactory DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory; defaultListableBeanFactory.registerBeanDefinition("personDao",beanDefinition); } }beans.xml<bean class="processor.MyBeanFactoryPostProcessor"/>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); PersonDao personDao = applicationContext.getBean(PersonDao.class); System.out.println(personDao); }执行结果beanDefinitionMap填充完毕后回调该方法 org.example.PersonDaoImpl@780cb77_Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作直接继承BeanDefinitionRegistryPostProcessor接口的方式简化代码MyBeanDefinitionRegistryPostProcessor.javapackage processor; import org.example.PersonDaoImpl; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { System.out.println("beanDefinitionMap填充完毕后回调该方法"); //注册BeanDefinition BeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClassName(PersonDaoImpl.class.getName()); beanDefinitionRegistry.registerBeanDefinition("personDao",beanDefinition); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { } } beans.xml<bean class="processor.MyBeanDefinitionRegistryPostProcessor"/>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); PersonDao personDao = applicationContext.getBean(PersonDao.class); System.out.println(personDao); }执行结果beanDefinitionMap填充完毕后回调该方法 org.example.PersonDaoImpl@50a7bc6e1.4使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描要求如下:自定义@MyComponent注解,使用在类上;使用资料中提供好的包扫描器工具BaseClassScanUtils 完成指定包的类扫描自定义BeanFactoryPostProcessor完成注解@MyComponent的解析,解析后最终被Spring管理。黑马程序员提供的BaseClassScanUtils.javapackage com.itheima.utils; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.util.ClassUtils; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.List; import java.util.Map; public class BaseClassScanUtils { //设置资源规则 private static final String RESOURCE_PATTERN = "/**/*.class"; public static Map<String, Class> scanMyComponentAnnotation(String basePackage) { //创建容器存储使用了指定注解的Bean字节码对象 Map<String, Class> annotationClassMap = new HashMap<String, Class>(); //spring工具类,可以获取指定路径下的全部类 ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); try { String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(basePackage) + RESOURCE_PATTERN; Resource[] resources = resourcePatternResolver.getResources(pattern); //MetadataReader 的工厂类 MetadataReaderFactory refractory = new CachingMetadataReaderFactory(resourcePatternResolver); for (Resource resource : resources) { //用于读取类信息 MetadataReader reader = refractory.getMetadataReader(resource); //扫描到的class String classname = reader.getClassMetadata().getClassName(); Class<?> clazz = Class.forName(classname); //判断是否属于指定的注解类型 if(clazz.isAnnotationPresent(MyComponent.class)){ //获得注解对象 MyComponent annotation = clazz.getAnnotation(MyComponent.class); //获得属value属性值 String beanName = annotation.value(); //判断是否为"" if(beanName!=null&&!beanName.equals("")){ //存储到Map中去 annotationClassMap.put(beanName,clazz); continue; } //如果没有为"",那就把当前类的类名作为beanName annotationClassMap.put(clazz.getSimpleName(),clazz); } } } catch (Exception exception) { } return annotationClassMap; } public static void main(String[] args) { Map<String, Class> stringClassMap = scanMyComponentAnnotation("com.itheima"); System.out.println(stringClassMap); } }由于我使用的是jdk19,所以使用上述文件会提示版本错误,所以在上面的基础上进行修改package utils; import anno.MyComponent; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.util.ClassUtils; import java.util.HashMap; import java.util.Map; public class BaseClassScanUtils { //设置资源规则 private static final String RESOURCE_PATTERN = "/**/*.class"; public static Map<String, Class> scanMyComponentAnnotation(String basePackage) { //创建容器存储使用了指定注解的Bean字节码对象 Map<String, Class> annotationClassMap = new HashMap<String, Class>(); //spring工具类,可以获取指定路径下的全部类 ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); try { String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(basePackage) + RESOURCE_PATTERN; Resource[] resources = resourcePatternResolver.getResources(pattern); for (Resource resource : resources) { Class<?> clazz = Class.forName(resource.getFile().toString().split("classes\\\\")[1].replaceAll("\\\\",".").split(".class")[0]); //判断是否属于指定的注解类型 if(clazz.isAnnotationPresent(MyComponent.class)){ //获得注解对象 MyComponent annotation = clazz.getAnnotation(MyComponent.class); //获得属value属性值 String beanName = annotation.value(); //判断是否为"" if(beanName!=null&&!beanName.equals("")){ //存储到Map中去 annotationClassMap.put(beanName,clazz); continue; } //如果没有为"",那就把当前类的类名作为beanName annotationClassMap.put(clazz.getSimpleName(),clazz); } } } catch (Exception exception) { System.out.println(exception); } return annotationClassMap; } public static void main(String[] args) { Map<String, Class> stringClassMap = scanMyComponentAnnotation("beans"); System.out.println(stringClassMap); } }创建注解MyComponentpackage anno; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyComponent { String value(); }创建类并且添加MyComponent注解,类位于beans目录下package beans; import anno.MyComponent; @MyComponent("otherBean") public class OtherBean { }创建新的后工厂处理器类,并且继承BeanDefinitionRegistryPostProcessor接口package processor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; import utils.BaseClassScanUtils; import java.util.Map; public class MyComponentBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { // 使用扫描工具去扫描指定包以及子包下的所有类,收集使用@Mycomponent的注解的类 Map<String, Class> myComponentAnnotation = BaseClassScanUtils.scanMyComponentAnnotation("beans"); // 遍历Map,组装BeanDefinition进行注册 myComponentAnnotation.forEach((beanName,clazz)->{ // 获取类名 String beanClassName = clazz.getName(); // 创建BeanDefinition BeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClassName(beanClassName); // 注册BeanDefinition beanDefinitionRegistry.registerBeanDefinition(beanName ,beanDefinition); }); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { } } 在beans.xml中添加后工厂处理器<bean class="processor.MyComponentBeanFactoryPostProcessor"/>主函数调用public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); OtherBean otherBean = applicationContext.getBean(OtherBean.class); System.out.println(otherBean); }执行结果beans.OtherBean@2133814f2. BeanPostProcessor2.1 快速入门Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如: 属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。BeanPostProcessor类public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }UserDaopackage org.example; public interface UserDao { }UserDaoImplpackage org.example; public class UserDaoImpl implements UserDao { String name; public UserDaoImpl() { System.out.println("UserDaoImpl初始化"); } public String getName() { return name; } public void setName(String name) { System.out.println("设置name的值为" + name); this.name = name; } }创建MyBeanPostProcessor并且继承BeanPostProcessor接口public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("before-" + beanName + ":" + bean.toString()); if (bean instanceof UserDaoImpl){ UserDaoImpl userDao = (UserDaoImpl) bean; userDao.setName("hhhhh"); } return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName); } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("after-" + beanName + ":" + bean.toString()); return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName); } }beans.xml<bean class="processor.MyBeanPostProcessor"/> <bean class="org.example.UserDaoImpl" id="userDao"/>主函数执行public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserDaoImpl userDao = (UserDaoImpl) applicationContext.getBean("userDao"); System.out.println(userDao.getName()); }执行结果UserDaoImpl初始化 before-userDao:org.example.UserDaoImpl@646be2c3 设置name的值为hhhhh after-userDao:org.example.UserDaoImpl@646be2c3 hhhhh2.2 before和after方法的执行时机基于上述快速入门的文件进行修改UserDaoImpl.javapackage org.example; import org.springframework.beans.factory.InitializingBean; public class UserDaoImpl implements UserDao, InitializingBean { public UserDaoImpl() { System.out.println("UserDaoImpl初始化"); } String name; public String getName() { return name; } public void setName(String name) { System.out.println("设置name的值为" + name); this.name = name; } public void init(){ System.out.println("init初始化方法执行"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("属性设置之后执行"); } }beans.xml<bean class="org.example.UserDaoImpl" id="userDao" init-method="init"/> <bean class="processor.MyBeanPostProcessor" />执行结果UserDaoImpl初始化 before-userDao:org.example.UserDaoImpl@3c0a50da 设置name的值为hhhhh 属性设置之后执行 init初始化方法执行 after-userDao:org.example.UserDaoImpl@3c0a50da hhhhh2.3 对Bean方法进行执行时间日志增强需求:Bean的方法执行之前控制台打印当前时间Bean的方法执行之后控制台打印当前时间分析:对方法进行增强主要就是代理设计模式和包装设计模式由于Bean方法不确定,所以使用动态代理在运行期间执行增强操作在Bean实例创建完毕后,进入到单例池之前,使用Proxy代替真是的目标BeanUserDao.javapackage org.example; public interface UserDao { public void show(); }UserDaoImpl.javapackage org.example; public class UserDaoImpl implements UserDao { public void show(){ System.out.println("执行方法中"); } }TimeLogBeanPostProcessor.javapackage processor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Date; public class TimeLogBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), (Object proxy, Method method, Object[] args) -> { //1.输出开始时间 System.out.println("方法:" + method.getName() + "-开始时间:" + new Date()); //2.执行目标方法 Object result = method.invoke(bean,args); //3.输出结束时间 System.out.println("方法:" + method.getName() + "-结束时间:" + new Date()); return result; }); return beanProxy; } }beans.xml<bean class="processor.TimeLogBeanPostProcessor"/> <bean class="org.example.UserDaoImpl" id="userDao"/>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.show(); }执行结果方法:show-开始时间:Thu Mar 02 16:13:42 CST 2023 执行方法中 方法:show-结束时间:Thu Mar 02 16:13:43 CST 2023
2023年03月02日
122 阅读
0 评论
0 点赞
2023-02-28
Java Spring Bean实例化的基本流程
Java Spring Bean实例化的基本流程Spring容器在进行初始化时,会将xml配置的<bean>的信息封装成一个BeanDefinition对象,所有的BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去,Spring框架在对该Map进行遍历,使用反射创建Bean实例对象,创建好的Bean对象存储在一个名为singletonObjects的Map集合中,当调用getBean方法时则最终从该Map集合中取出Bean实例对象返回。流程:加载xml配置文件,解析获取配置中的每个<bean>的信息,封装成一个个的BeanDefinition对象将BeanDefinition存储在一个名为beanDefinitionMap的Map<String,BeanDefinition>中;ApplicationContext底层遍历beanDefinitionMap,创建Bean实例对象 创建好的Bean实例对象,被存储到一个名为singletonObjects的Map<String,Object>中;当执行applicationContext.getBean(beanName)时,从singletonObjects去匹配Bean实例返回beans.xml <bean class="org.example.UserDaoImpl" id="userDao"/> <bean class="org.example.UserServiceImpl" id="userService"/>主函数断点调试运行 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); }Bean信息定义对象-BeanDefinitionBeanDefinition.class// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.beans.factory.config; import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.MutablePropertyValues; import org.springframework.core.AttributeAccessor; import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { String SCOPE_SINGLETON = "singleton"; String SCOPE_PROTOTYPE = "prototype"; int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRASTRUCTURE = 2; void setParentName(@Nullable String var1); @Nullable String getParentName(); void setBeanClassName(@Nullable String var1); @Nullable String getBeanClassName(); void setScope(@Nullable String var1); @Nullable String getScope(); void setLazyInit(boolean var1); boolean isLazyInit(); void setDependsOn(@Nullable String... var1); @Nullable String[] getDependsOn(); void setAutowireCandidate(boolean var1); boolean isAutowireCandidate(); void setPrimary(boolean var1); boolean isPrimary(); void setFactoryBeanName(@Nullable String var1); @Nullable String getFactoryBeanName(); void setFactoryMethodName(@Nullable String var1); @Nullable String getFactoryMethodName(); ConstructorArgumentValues getConstructorArgumentValues(); default boolean hasConstructorArgumentValues() { return !this.getConstructorArgumentValues().isEmpty(); } MutablePropertyValues getPropertyValues(); default boolean hasPropertyValues() { return !this.getPropertyValues().isEmpty(); } void setInitMethodName(@Nullable String var1); @Nullable String getInitMethodName(); void setDestroyMethodName(@Nullable String var1); @Nullable String getDestroyMethodName(); void setRole(int var1); int getRole(); void setDescription(@Nullable String var1); @Nullable String getDescription(); ResolvableType getResolvableType(); boolean isSingleton(); boolean isPrototype(); boolean isAbstract(); @Nullable String getResourceDescription(); @Nullable BeanDefinition getOriginatingBeanDefinition(); }
2023年02月28日
86 阅读
0 评论
0 点赞
2023-02-27
Java Spring 配置非自定义Bean
Java Spring 配置非自定义Bean0.介绍实际开发中会使用第三方jar包中的功能类,这些Bean要想让Spring进行管理,也需要对其进行配置两个问题:被配置的Bean实例化方式是什么被配置的Bean是否需要注入必要属性1.配置Druid数据源交由Spring管理maven配置文件导入相应jar包pom.xml <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.23</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency>beans.xml <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/java"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object dataSource = applicationContext.getBean("dataSource"); System.out.println(dataSource); }运行结果{ CreateTime:"2023-02-26 17:23:51", ActiveCount:0, PoolingCount:0, CreateCount:0, DestroyCount:0, CloseCount:0, ConnectCount:0, Connections:[ ] }2.配置Connection交由Spring管理Connection的产生是通过DriverManager的静态方法getConnection获取的,所以我们要用静态工厂的方式配置beans.xml(getConnection报红不用管) <bean id="connection" class="java.sql.DriverManager" factory-method="getConnection" scope="prototype"> <constructor-arg name="url" value="jdbc:mysql://localhost:3306/java"/> <constructor-arg name="user" value="root"/> <constructor-arg name="password" value="root"/> </bean>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object connection = applicationContext.getBean("connection"); System.out.println(connection);; }执行结果(报错不用管,看到有类字节码地址输出即可)com.mysql.jdbc.JDBC4Connection@42a15bdc3.配置日期对象交由Spring管理原生使用日期对象 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = simpleDateFormat.parse("2023-08-27 12:00:00"); System.out.println(date);结果输出Sun Aug 27 12:00:00 CST 2023配置日期对象交由Spring管理beans.xml <bean id="simpleDateFormat" class="java.text.SimpleDateFormat"> <constructor-arg name="pattern" value="yyyy-MM-dd HH:mm:ss"/> </bean> <bean id="date" factory-bean="simpleDateFormat" factory-method="parse"> <constructor-arg name="source" value="2023-08-27 12:00:00"/> </bean>主函数执行 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Object date1 = applicationContext.getBean("date"); System.out.println(date1);结果输出Sun Aug 27 12:00:00 CST 20234.配置MyBatis的SqlSessionFactory交由Spring管理导入MyBatis的相关坐标 <!-- mybatis框架 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency>4.1 原生实现 // 静态工厂方法方式 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 无参构造实例化 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 实例工厂方法 SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); System.out.println(sqlSessionFactory);执行结果org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@79efed2d4.2 Bean实现resources目录下创建mybatis-config.xml<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/java"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> </configuration>beans.xml <!-- 静态工厂方法 --> <bean id="resources" class="org.apache.ibatis.io.Resources" factory-method="getResourceAsStream"> <constructor-arg name="resource" value="mybatis-config.xml"/> </bean> <!-- 无参构造实例化 --> <bean id="sqlSessionFactoryBuilder" class="org.apache.ibatis.session.SqlSessionFactoryBuilder"/> <!-- 实例工厂方法 --> <bean id="sqlSessionFactory" factory-bean="sqlSessionFactoryBuilder" factory-method="build"> <constructor-arg name="inputStream" ref="resources"/> </bean>主函数调用 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object sqlSessionFactory = applicationContext.getBean("sqlSessionFactory"); System.out.println(sqlSessionFactory);执行结果org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@5026735c
2023年02月27日
134 阅读
0 评论
0 点赞
1
2
3