# 通过 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 = 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 注入方式。