HTML asp 网站,做网站的开发环境,2022没封的网站免费的,网站开发研究资料书籍问题
对于一些使用建造者模式的 Bean#xff0c;我们往往不能直接 new 出来#xff0c;这些 Bean 如果需要注册到 Spring 容器中#xff0c;我们就需要使用工厂类。
比如我们项目中经常使用的okhttp: 如果我们想把OkHttpClient注册到Spring容器中#xff0c;该怎么做?
…问题
对于一些使用建造者模式的 Bean我们往往不能直接 new 出来这些 Bean 如果需要注册到 Spring 容器中我们就需要使用工厂类。
比如我们项目中经常使用的okhttp: 如果我们想把OkHttpClient注册到Spring容器中该怎么做?
public class App {public static void main(String[] args) {//通过建造者模式去创建 OkHttpClient 对象OkHttpClient client new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();//构建一个具体的请求Request getRequest new Request.Builder().get().url(https://www.baidu.com).build();Call call client.newCall(getRequest);CountDownLatch countDownLatch new CountDownLatch(1);//异步执行网络请求处理请求结果如果直接调用call.execute()就是同步会阻塞call.enqueue(new Callback() {Overridepublic void onFailure(NotNull Call call, NotNull IOException e) {countDownLatch.countDown();}// 这个就是请求成功的回调函数Overridepublic void onResponse(NotNull Call call, NotNull Response response) throws IOException {countDownLatch.countDown();System.out.println(response.body().string() response.body().string());}});//会判断计数器是否为 0如果为 0才会继续执行后续的代码否则就暂停在这里try {countDownLatch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}}
}又比如GSON: 这里的Gson对象也不是直接 new 出来的而是通过一个GsonBuilder对象建造出来的。
public class App {public static void main(String[] args) {User user new User();user.setName(hogen);user.setBirthday(new Date());Gson gson new GsonBuilder().setDateFormat(yyyy-MM-dd HH:mm:ss).create();String toJson gson.toJson(user);System.out.println(toJson);
}解决方案
方法一 静态工厂
通过一个工厂方法将 Bean 构建好之后注入到 Spring 容器中需要注意的是这个工厂方法是一个静态方法
// 静态工厂顾名思义可以直接通过类名.方法名调用
public class OkHttpClientStaticFactory {private static OkHttpClient okHttpClient;static {okHttpClient new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();}public static OkHttpClient getInstance() {return okHttpClient;}
}然后在 XML 文件中配置静态工厂
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdbean classorg.example.OkHttpClientStaticFactory idokHttpClient factory-methodgetInstance/
/beansXML 中配置的时候需要注意虽然我们看起来向 Spring 容器中注册的是一个静态工厂类的对象但是实际上最终会调用对应的方法 factory-method向 Spring 容器中注册一个 OkHttpClient 对象而且该对象还是单例的。
public class App {public static void main(String[] args) {ClassPathXmlApplicationContext ctx new ClassPathXmlApplicationContext(beans.xml);OkHttpClient client1 ctx.getBean(okHttpClient, OkHttpClient.class);OkHttpClient client2 ctx.getBean(okHttpClient, OkHttpClient.class);System.out.println(client2 client2);System.out.println(client2 client1);}
}输出
client2 okhttp3.OkHttpClient41fecb8b
true方法一 实例工厂
此种情况工厂方法是一个实例方法(得先有对象再调用方法)。
public class OkHttpClientStaticFactory {private static OkHttpClient okHttpClient;static {okHttpClient new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();}public static OkHttpClient getInstance() {return okHttpClient;}
}然后在 XML 文件中进行配置
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdbean classorg.example.OkHttpClientInstanceFactory idokHttpClientInstanceFactory/bean classorg.example.OkHttpClientInstanceFactory factory-beanokHttpClientInstanceFactory factory-methodgetInstance idokHttpClient/
/beans那么需要注意的是实例工厂中工厂方法无法直接调用必须先有一个实例对象然后才能调用工厂方法。当然最终注册到 Spring 容器中的 Bean 也是单例的。
ClassPathXmlApplicationContext ctx new ClassPathXmlApplicationContext(beans.xml);
OkHttpClient client1 ctx.getBean(okHttpClient, OkHttpClient.class);
OkHttpClient client2 ctx.getBean(okHttpClient, OkHttpClient.class);
System.out.println(client2 client2);
System.out.println(client2 client1);方法一 FactoryBean推荐)
这种是开发中使用较多的一种方案。SqlSessionFactoryBean 、 ShiroFilterFactoryBean 。。。 首先我们需要创建一个 OkHttpClientFactoryBean
/*** 注意这个命名是有规则的一般叫做 xxxFactoryBean看到这个名字就知道最终生成的 Bean 实际上是 xxx*/
public class OkHttpClientFactoryBean implements FactoryBeanOkHttpClient {/*** 返回具体的实例对象** return* throws Exception*/Overridepublic OkHttpClient getObject() throws Exception {return new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();}/*** 返回的实例对象的类型** return*/Overridepublic Class? getObjectType() {return OkHttpClient.class;}/*** 是否是单例模式* 如果为 false就相当于 scope 为 prototype默认该值为 true** return*/Overridepublic boolean isSingleton() {return FactoryBean.super.isSingleton();}
}然后在 XML 文件中进行配置
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdbean classorg.example.OkHttpClientFactoryBean idokHttpClient/
/beans当然最终获取到的还是okHttpClient对象
public class App {public static void main(String[] args) {ClassPathXmlApplicationContext ctx new ClassPathXmlApplicationContext(beans.xml);OkHttpClient okHttpClient ctx.getBean(okHttpClient, OkHttpClient.class);System.out.println(okHttpClient);}
}输出
okhttp3.OkHttpClient693fe6c9那么如何获取到这个工厂 Bean 呢只需要 id 前面添加一个 符号就可以获取到 FactoryBean。
public class App {public static void main(String[] args) {ClassPathXmlApplicationContext ctx new ClassPathXmlApplicationContext(beans.xml);Object bean ctx.getBean(okHttpClient);System.out.println(bean.getClass());}
}输出
class org.example.OkHttpClientFactoryBean