update
This commit is contained in:
parent
939c510f21
commit
47227f523a
94
java/spring.md
Normal file
94
java/spring.md
Normal file
@ -0,0 +1,94 @@
|
||||
# 通过 Spring 5 中 Supplier 来获取 Bean
|
||||
|
||||
|
||||
|
||||
Spring5 中开始提供了 `Supplier`,可以通过接口回调获取到一个 Bean 的实例,这种方式显然性能更好一些。
|
||||
|
||||
如下:
|
||||
|
||||
```java
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
GenericBeanDefinition definition = new GenericBeanDefinition();
|
||||
definition.setBeanClass(Book.class);
|
||||
definition.setInstanceSupplier((Supplier<Book>) () -> {
|
||||
Book book = new Book();
|
||||
book.setName("深入浅出 Spring Security");
|
||||
book.setAuthor("江南一点雨");
|
||||
return book;
|
||||
});
|
||||
ctx.registerBeanDefinition("b1", definition);
|
||||
ctx.refresh();
|
||||
Book b = ctx.getBean("b1", Book.class);
|
||||
System.out.println("b = " + b);
|
||||
```
|
||||
|
||||
关键就是通过调用 `BeanDefinition` 的 `setInstanceSupplier` 方法去设置回调。当然,上面这段代码还可以通过 *Lambda* 进一步简化:
|
||||
|
||||
```java
|
||||
public class BookSupplier {
|
||||
public Book getBook() {
|
||||
Book book = new Book();
|
||||
book.setName("深入浅出 Spring Security");
|
||||
book.setAuthor("江南一点雨");
|
||||
return book;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
然后调用这个方法即可:
|
||||
|
||||
```java
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
GenericBeanDefinition definition = new GenericBeanDefinition();
|
||||
definition.setBeanClass(Book.class);
|
||||
BookSupplier bookSupplier = new BookSupplier();
|
||||
definition.setInstanceSupplier(bookSupplier::getBook);
|
||||
ctx.registerBeanDefinition("b1", definition);
|
||||
ctx.refresh();
|
||||
Book b = ctx.getBean("b1", Book.class);
|
||||
System.out.println("b = " + b);
|
||||
```
|
||||
|
||||
这是不是更有一点 *Lambda* 的感觉了?
|
||||
|
||||
在 Spring 源码中,处理获取 Bean 实例的时候,有如下一个分支,就是处理 `Supplier` 这种情况的:
|
||||
|
||||
```
|
||||
AbstractAutowireCapableBeanFactory#createBeanInstance
|
||||
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
|
||||
// Make sure bean class is actually resolved at this point.
|
||||
Class<?> beanClass = resolveBeanClass(mbd, beanName);
|
||||
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
|
||||
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
|
||||
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
|
||||
}
|
||||
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
|
||||
if (instanceSupplier != null) {
|
||||
return obtainFromSupplier(instanceSupplier, beanName);
|
||||
}
|
||||
if (mbd.getFactoryMethodName() != null) {
|
||||
return instantiateUsingFactoryMethod(beanName, mbd, args);
|
||||
}
|
||||
//...
|
||||
return instantiateBean(beanName, mbd);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName) {
|
||||
String outerBean = this.currentlyCreatedBean.get();
|
||||
this.currentlyCreatedBean.set(beanName);
|
||||
try {
|
||||
if (supplier instanceof InstanceSupplier<?> instanceSupplier) {
|
||||
return instanceSupplier.get(RegisteredBean.of((ConfigurableListableBeanFactory) this, beanName));
|
||||
}
|
||||
if (supplier instanceof ThrowingSupplier<?> throwableSupplier) {
|
||||
return throwableSupplier.getWithException();
|
||||
}
|
||||
return supplier.get();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
上面 `obtainFromSupplier` 这个方法,最终会调用到第二个方法。第二个方法中的 `supplier.get();` 其实最终就调用到我们自己写的 `getBook` 方法了。
|
||||
|
||||
如上,这是从 Spring5 开始结合 Lamdba 的一种 Bean 注入方式。
|
Loading…
x
Reference in New Issue
Block a user