网站优化图片链接怎么做,南京制作网站要多少钱,怎么样建立自己的视频网站,app开发及后期维护费用FactoryBean 首先是一个工厂类#xff0c;它可以生产指定的Bean#xff0c;特殊之处在于它可以向Spring容器中注册两个Bean#xff0c;一个是它本身#xff0c;一个是FactoryBean.getObject()方法返回值所代表的Bean。通过实现 FactoryBean 接口#xff0c;你可以控制某个… FactoryBean 首先是一个工厂类它可以生产指定的Bean特殊之处在于它可以向Spring容器中注册两个Bean一个是它本身一个是FactoryBean.getObject()方法返回值所代表的Bean。通过实现 FactoryBean 接口你可以控制某个 Bean 的实例化过程提供比默认机制更复杂的创建逻辑。 FactoryBean接口
public interface FactoryBeanT {NullableT getObject() throws Exception;NullableClass? getObjectType();default boolean isSingleton() {return true;}
}FactoryBean 接口包含三个核心方法
Object getObject() throws Exception 返回由 FactoryBean 创建的 bean 实例。这是 FactoryBean 最重要的方法通过这个方法你可以自定义 bean 的创建逻辑。Class? getObjectType() 返回由 FactoryBean 创建的 bean 实例的类型。这个方法用于告诉 Spring 容器这个工厂 bean 创建的对象的类型以便在需要时进行类型转换和检查。boolean isSingleton() 返回由 FactoryBean 创建的 bean 实例是否是单例的。如果返回 true那么 Spring 容器会将创建的对象作为单例进行管理如果返回 false每次请求都会创建一个新的实例。
重要事项
FactoryBean表现的是一个工厂的职责。 即一个Bean A如果实现了FactoryBean接口那么A就变成了一个工厂根据A的名称获取到的实际上是工厂调用getObject()返回的对象而不是A本身如果要获取工厂A自身的实例那么需要在名称前面加上’符号。详情请看实例演示。
实例演示
定义学生类
注意这个类并没有被Component等注解标注即没有被Spring容器管理。
public class Student {private Logger logger LoggerFactory.getLogger(Student.class);public Student(){logger.info(Hi, I am a good student!);}
}定义StudentFactoryBean
package com.example.jaytecharchite.factorybeandemo;
Component
public class StudentFactoryBean implements FactoryBean {Overridepublic Object getObject() throws Exception {return new Student();}Overridepublic Class? getObjectType() {return Student.class;}Overridepublic boolean isSingleton() {// return false; 非单例return FactoryBean.super.isSingleton(); //默认true单例工厂}
}很简单我们让这个工厂类生成学生类注意看getObjectType()返回的Class类型和getObject()返回的实例一致其实也可以不一致当我们问Spring容器通过Student student applicationContext.getBean(Student.class);这一句代码向Spring容器获取Bean时其实它是通过getObjectType()来找到生产这个类型的工厂从而调用getObject()获取到实例。
配置类
需要配置类将StudentFactoryBean注册到Spring容器中。
Configuration
ComponentScan(com.example.jaytecharchite)
public class AppConfig {
}测试
SpringBootTest
public class MainTest {private Logger logger LoggerFactory.getLogger(CallBackTest.class);Testpublic void test(){AnnotationConfigApplicationContext applicationContext new AnnotationConfigApplicationContext(AppConfig.class);logger.info(容器启动完成);Student student applicationContext.getBean(Student.class);System.out.println(student);Student student2 applicationContext.getBean(Student.class);System.out.println(student2);Object student3 applicationContext.getBean(studentFactoryBean);System.out.println(student3);Object customerFactoryBean2 applicationContext.getBean(studentFactoryBean);System.out.println(customerFactoryBean2);}
}输出
如果isSingleton()返回的是true则输出结果如下 2024-07-03 22:37:38.961 INFO 21112 — [ main] c.e.j.xxxaware.CallBackTest : 容器启动完成 2024-07-03 22:37:38.962 INFO 21112 — [ main] c.e.j.factorybeandemo.Student : Hi, I am a good student! com.example.jaytecharchite.factorybeandemo.Student5c887052 com.example.jaytecharchite.factorybeandemo.Student5c887052 com.example.jaytecharchite.factorybeandemo.Student5c887052 com.example.jaytecharchite.factorybeandemo.StudentFactoryBean55fdf7f9 可以看见前三个获取到的Bean都是getObejct()方法的Bean并且是同一个Bean因为是设置了单例模式。而最后一个使用了符号获取到的才是 StudentFactoryBean本身的实例。
如果isSingleton()返回的是false则输出结果如下 2024-07-03 22:40:58.104 INFO 4416 — [ main] c.e.j.xxxaware.CallBackTest : 容器启动完成 2024-07-03 22:40:58.105 INFO 4416 — [ main] c.e.j.factorybeandemo.Student : Hi, I am a good student! com.example.jaytecharchite.factorybeandemo.Student72b6832e 2024-07-03 22:40:58.105 INFO 4416 — [ main] c.e.j.factorybeandemo.Student : Hi, I am a good student! com.example.jaytecharchite.factorybeandemo.Student3850e90c 2024-07-03 22:40:58.105 INFO 4416 — [ main] c.e.j.factorybeandemo.Student : Hi, I am a good student! com.example.jaytecharchite.factorybeandemo.Student3d9f5016 com.example.jaytecharchite.factorybeandemo.StudentFactoryBean7e91ed74 可以看见前三个Bean都是不同的对象实例并且每个实例都会执行一次构造方法。我们自定义的StudentFactoryBean实现了FactoryBean接口所以当StudentFactoryBean被扫描进Spring容器时实际上它向容器中注册了两个bean一个是StudentFactoryBean类的单例对象另外一个就是getObject()方法返回的对象在demo中我们重写的getObject()方法中我们通过new Student()返回了一个Student的实例对象所以我们从容器中能获取到Student的实例对象。如果我们想通过beanName去获取StudentFactoryBean的单例对象需要在beanName前面添加一个符号这样就能根据beanName获取到原生对象了。否则获取到的还是getObject()提供的对象。
FactoryBean 的使用场景
FactoryBean 的使用场景包括但不限于
创建复杂对象 当对象的创建过程非常复杂无法通过简单的构造函数或静态工厂方法实现时可以使用 FactoryBean。例如创建带有复杂初始化逻辑的数据库连接对象、远程服务代理等。动态代理 使用 FactoryBean 可以方便地创建动态代理对象特别是在 AOP面向切面编程和远程调用场景中。单例和多例模式 通过 isSingleton 方法可以灵活地控制 bean 的作用域。
神级现场
在MyBatis中只需要写个接口就能实现就能运行SQL你不觉得奇怪吗难道你的接口MyBatis自动帮你实现了非也MyBatis并没有去实现你的接口那么你会问那为什么直接可以调用接口这就是FactoryBeanProxy的神级现场设计下面为了简答只演示调用接口就实现功能。
学生接口
public interface Student {void say();
}代理工厂Bean /*** 这里根本没有Student的实现类只有一个接口在代理中实现了接口的方法* param T*/
Component
public class StudentFactoryBeanProxyT implements FactoryBeanT {/*** 通过 FactoryBean 创建代理对象Bean* return 一个代理对象* throws Exception*/Overridepublic T getObject() throws Exception {// 创建了一个 InvocationHandler 对象用于处理代理对象的方法调用InvocationHandler handler (proxy, method, args) - {String name method.getName();if (say.equals(name)) {System.out.println(Hi, I am a good student!);}return 只要拿到接口就能在代理中实现任何功能;};// 使用 Proxy.newProxyInstance() 方法创建代理对象也就是外部的接口其实是一个代理对象return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{Student.class}, handler);}Overridepublic Class? getObjectType() {return Student.class;}
}配置类
Configuration
ComponentScan(com.example.jaytecharchite.factorybeandemo2)
public class MyConfig {
}测试
public class MainTest {private Logger logger LoggerFactory.getLogger(MainTest.class);Autowiredprivate Student student; // 其实这个就是一个代理对象只不过名字还是StudentTestpublic void test(){AnnotationConfigApplicationContext applicationContext new AnnotationConfigApplicationContext(MyConfig.class);logger.info(容器启动完成);student.say();}
}输出 2024-07-03 23:24:36.144 INFO 17080 — [ main] c.e.j.factorybeandemo2.MainTest : 容器启动完成 Hi, I am a good student! 注意看我们并没有实现Student哦但是它调用student.say();就能说话神级现场