update
This commit is contained in:
		
							
								
								
									
										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 注入方式。 | ||||
		Reference in New Issue
	
	Block a user