隐式构造函数注入
考虑以下服务类:
@Service
public class FooService {
private final FooRepository repository;
@Autowired
public FooService(FooRepository repository) {
this.repository = repository
}
}
这是常见场景,但忘记在构造函数上加 @Autowired
会导致容器抛出异常(除非显式配置)。Spring 4.3 开始,单构造函数场景下无需显式注入注解:
public class FooService {
private final FooRepository repository;
public FooService(FooRepository repository) {
this.repository = repository
}
}
在 Spring 4.2 及以下版本,以下 XML 配置会因找不到默认构造函数而失败。Spring 4.3 则能自动注入:
<beans>
<bean class="com.baeldung.spring43.ctor.FooRepository" />
<bean class="com.baeldung.spring43.ctor.FooService" />
</beans>
同理,@Configuration
类现在也支持构造函数注入,单构造函数时可省略 @Autowired
:
@Configuration
public class FooConfiguration {
private final FooRepository repository;
public FooConfiguration(FooRepository repository) {
this.repository = repository;
}
@Bean
public FooService fooService() {
return new FooService(this.repository);
}
}
Java 8 默认接口方法支持
Spring 4.3 前不支持默认接口方法(因 JDK 的 JavaBean 内省器不识别默认方法)。现在注入时能识别默认方法实现的 getter/setter:
public interface IDateHolder {
void setLocalDate(LocalDate localDate);
LocalDate getLocalDate();
default void setStringDate(String stringDate) {
setLocalDate(LocalDate.parse(stringDate,
DateTimeFormatter.ofPattern("dd.MM.yyyy")));
}
}
现在可通过 stringDate
属性注入:
<bean id="dateHolder"
class="com.baeldung.spring43.defaultmethods.DateHolder">
<property name="stringDate" value="15.10.1982"/>
</bean>
测试注解(如 @BeforeTransaction
)同样支持默认接口方法。JUnit 5 已支持,Spring 4.3 跟进。可抽象测试逻辑到接口:
public interface ITransactionalTest {
Logger log = LoggerFactory.getLogger(ITransactionalTest.class);
@BeforeTransaction
default void beforeTransaction() {
log.info("Before opening transaction");
}
@AfterTransaction
default void afterTransaction() {
log.info("After closing transaction");
}
}
额外福利:@BeforeTransaction
、@AfterTransaction
和 @Transactional
注解的方法不再要求 public
,任意可见性均可。
依赖解析增强
Spring 4.3 引入 ObjectProvider
(扩展 ObjectFactory
),提供便捷方法:
-
getIfAvailable
- 仅当 Bean 存在时获取 -
getIfUnique
- 仅当存在唯一候选 Bean 时获取(多匹配时取 primary)
@Service
public class FooService {
private final FooRepository repository;
public FooService(ObjectProvider<FooRepository> repositoryProvider) {
this.repository = repositoryProvider.getIfUnique();
}
}
可用于初始化时自定义解析,或存储句柄用于延迟按需解析(类似 ObjectFactory
用法)。
缓存抽象优化
缓存抽象常用于 CPU/IO 密集型操作。某些场景(如启动)多个线程可能并行请求同一 key。Spring 4.3 新增同步缓存支持:
@Service
public class FooService {
@Cacheable(cacheNames = "foos", sync = true)
public Foo getFoo(String id) { ... }
}
sync = true
确保值计算时阻塞并发线程,避免重复计算。其他优化包括:
- 缓存注解元数据改进
- 缓存解析器增强
- 缓存管理器配置简化
组合式 @RequestMapping 变体
Spring 4.3 新增方法级组合注解,简化常见 HTTP 方法映射:
-
@GetMapping
=@RequestMapping(method = GET)
-
@PostMapping
=@RequestMapping(method = POST)
-
@PutMapping
=@RequestMapping(method = PUT)
-
@DeleteMapping
=@RequestMapping(method = DELETE)
-
@PatchMapping
=@RequestMapping(method = PATCH)
示例:
@Controller
@RequestMapping("/appointments")
public class AppointmentsController {
private final AppointmentBook appointmentBook;
@Autowired
public AppointmentsController(AppointmentBook appointmentBook) {
this.appointmentBook = appointmentBook;
}
@GetMapping
public Map<String, Appointment> get() {
return appointmentBook.getAppointmentsForToday();
}
}
@RequestScope, @SessionScope, @ApplicationScope 注解
使用注解驱动或 Java Config 时,可通过这些注解指定组件作用域:
-
@RequestScope
- 请求作用域 -
@SessionScope
- 会话作用域 -
@ApplicationScope
- 应用作用域
这些注解不仅设置作用域,还自动设置 ScopedProxyMode.TARGET_CLASS
(CGLIB 代理),确保 Bean 可注入到更广作用域的 Bean 中:
@RequestScope
@Component
public class LoginAction { ... }
@SessionScope
@Component
public class UserPreferences { ... }
@ApplicationScope
@Component
public class AppPreferences { ... }
@RequestAttribute 和 @SessionAttribute 注解
新增两个注解用于注入 HTTP 请求参数:
-
@RequestAttribute
- 访问请求属性 -
@SessionAttribute
- 访问会话属性
这些属性通常由全局组件(如 Filter
或 HandlerInterceptor
)设置。示例拦截器:
public class ParamInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
request.getSession().setAttribute("login", "john");
request.setAttribute("query", "invoices");
return super.preHandle(request, response, handler);
}
}
控制器中直接注入:
@GetMapping
public String get(@SessionAttribute String login,
@RequestAttribute String query) {
return String.format("login = %s, query = %s", login, query);
}
库与应用服务器版本支持
Spring 4.3 支持以下版本:
- Hibernate ORM 5.0+
- Jackson 2.6+
- OkHttp 3.x
- Netty 4.1
- Tomcat 8.5+
- WildFly 10
同时 spring-core.jar
内置升级版 ASM 5.1 和 Objenesis 2.4。
InjectionPoint 类
InjectionPoint
是 Spring 4.3 新增类,提供 Bean 注入点的详细信息(字段/方法参数/构造函数参数)。可获取:
- 注入字段对象(
getField()
) - 方法参数对象(
getMethodParameter()
) - 包含成员(
getMember()
) - 声明类型(
getDeclaredType()
) - 关联注解(
getAnnotations()
) - 注解元素(
getAnnotatedElement()
)
典型场景:按注入类创建 Logger:
@Bean
@Scope("prototype")
public Logger logger(InjectionPoint injectionPoint) {
return Logger.getLogger(
injectionPoint.getMethodParameter().getContainingClass());
}
注意:Bean 必须是 prototype 作用域,否则多注入点会返回首次遇到的注入点。使用示例:
@Autowired
private Logger logger;
总结
Spring 4.3 带来诸多实用改进:
- 注解简化 - 隐式构造注入、组合式映射注解、作用域注解
- 依赖注入增强 -
ObjectProvider
、InjectionPoint
- Web 层优化 - 属性注入注解、接口默认方法支持
- 缓存改进 - 同步缓存支持
这些特性大幅减少样板代码,提升开发效率。完整示例代码见 GitHub。