我继承了两个相当重要的代码库,它们使用spring来配置应用程序.现在我需要重新配置应用程序.但是通过自动装配提供了许多配置,因此几乎不可能找出实际配置是什么.
这些项目规模适中,每个项目有20个主题模块,包括集成测试模块等.大多数模块为各种目的定义了一些应用程序上下文,它们包含一个或两个本地spring配置文件以及它所依赖的核心模块中的一个或两个.结果是无数的配置,并且我不能改变类或变量名(或setter方法)而不会在某些上游或下游模块中破坏依赖性,即使项目中的任何地方都没有这样的依赖项.
如何在Spring中有效地使用自动连接的依赖项?
任何人,也许是真正喜欢自动装配的人,都可以提供一些有关如何有效地使用它们的见解吗?
(我还继承了一个小项目,它结合了xml文件,自动装配和注释驱动的配置,使得依赖关系完全难以处理,但我稍后会将这些注释保存为单独的问题)
我有一个String,我将自动装配为bean.该值的值String通过属性文件设置,并在运行时加载.我可以验证这一点.这是我的XML:
<context:property-placeholder location="classpath:my-app.properties" />
<bean id="loadedProp" class="java.lang.String">
<constructor-arg>
<value>${loaded-prop}</value>
</constructor-arg>
</bean>
Run Code Online (Sandbox Code Playgroud)
在我的应用程序中,我在bean中自动装配:
@Component
public class Foo {
@Autowired
private String loadedProp;
}
Run Code Online (Sandbox Code Playgroud)
一切都很好看.我有多个组件在这个bean中自动装配.我正在尝试做的是,在应用程序运行时,将bean的值更新为其他内容,以便在bean自动装配的任何地方,它使用最新的值.是否可以这样做,或者我只是需要在每次想要更改值时重新启动?
我有一个带弹簧配置文件的Web应用程序.我有以下条目:
<bean id="flyway" class="xxx.FlywayTool" init-method="migrateOrFail"/>
Run Code Online (Sandbox Code Playgroud)
"flyway"bean用于初始化和迁移数据库.现在我有另一个bean定义应用程序应该使用的数据源:
<bean id="dataSource" class="..." depends-on="flyway">
Run Code Online (Sandbox Code Playgroud)
这个取决于飞路取得成功.
一切都很好.现在,当"flyway"bean引发异常时,spring的引导停止并且webapp启动完成 - 一切都很好.
现在我开始通过以下方式为某些组件启用自动装配:
<context:component-scan base-package="de.xxxxx.xxxxx" />
Run Code Online (Sandbox Code Playgroud)
在某些类中,我依赖于服务,这些服务在xml配置中也被定义为bean.他们依赖于上面提到的数据源.
现在的问题是:一旦我现在引导应用程序并且"flyway"抛出一个异常,弹出就会在下一节中吞下异常:
org.springframework.beans.factory.support.AbstractBeanFactory.getTypeForFactoryBean(String,RootBeanDefinition)
catch (BeanCreationException ex) {
// Can only happen when getting a FactoryBean.
if (logger.isDebugEnabled()) {
logger.debug("Ignoring bean creation exception on FactoryBean type check: " + ex);
}
onSuppressedException(ex);
return null;
}
Run Code Online (Sandbox Code Playgroud)
现在是春天尝试,对于其他所有dependend服务(取决于数据源,因此flyway)初始化所有bean,这反过来导致相同的过程一次又一次.
这个特殊的循环一直持续到春天结束,试图在第一个飞路错误之后实现每个可能的依赖,而不是中止.
这种奇怪的行为只有在我启用组件扫描时才会启动
<context:component-scan ....
Run Code Online (Sandbox Code Playgroud)
当此功能被禁用时,弹簧在第一个飞路错误发生后停止.它也最终出现在另一个类中:
org.springframework.context.support.AbstractApplicationContext.refresh()
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate …Run Code Online (Sandbox Code Playgroud) 我正在开发一个连接MySQL数据库的非常小的应用程序.
我正在尝试创建表记录但是"没有正在进行的事务".
我有适当的东西:
但,
当我远程调试并检查控制器的myService字段时,我看到的是com.some.package.services.MyService@12345(而不是像$ Proxy73这样的东西)对我来说是不对的,因为应该自动装配的是代理不是他的目标豆(我认为这是).如果我是正确的,那么没有事务是有意义的,因为注释只会在调用在代理上使用@Transactional注释的公共方法时启动.
请告诉我为什么spring在这个设置中注入目标bean.
谢谢
我有一个抽象类:
@Component
public abstract class BaseReport {
public void export() {
...
}
Run Code Online (Sandbox Code Playgroud)
还有一堆扩展它的类,并覆盖export()方法(或不覆盖).
@Component
public final class Report1 extends BaseReport
@Component
public final class Report2 extends BaseReport
Run Code Online (Sandbox Code Playgroud)
我的大多数测试都会自动装配扩展BaseReport的具体类,没有任何问题:
public class Report1Test extends BaseTest {
@Autowired
Report1 _report;
public class Report2Test extends BaseTest {
@Autowired
Report2 _report;
Run Code Online (Sandbox Code Playgroud)
这适用于扩展 BaseReport 的所有类的自动装配.但是我还需要自动抽象抽象类本身BaseReport来测试export()方法.
public class BaseReportTest extends BaseTest {
@Autowired
BaseReport _report;
Run Code Online (Sandbox Code Playgroud)
当我尝试运行它时,我得到了臭名昭着的:
没有定义BaseReport类型的唯一bean:期望的单个匹配bean但找到2 [Report1,Report2].
我已经尝试过使用@Qualifier,但@Qualifier的问题是(据我所知)你用它来告诉Spring哪个类 - 实现一个接口或扩展一个Abstract类 - 你想使用它.但那不是我的情况.我想使用抽象类本身.
我也试过使用@Resource,像这样:
public class BaseReportTest extends BaseTest {
@Resource(name = "baseReport")
BaseReport _report; …Run Code Online (Sandbox Code Playgroud) 我是Spring的新手,所以我一直在寻找安全方面的东西.每次我运行我的应用程序时,我得到:
org.springframework.beans.factory.BeanCreationException:创建名为'securityConfig'的bean时出错:注入自动连接的依赖项失败; 嵌套异常是org.springframework.beans.factory.BeanCreationException:无法自动装配字段:private org.springframework.security.core.userdetails.UserDetailsService com.entirety.app.config.SecurityConfig.userDetailsServiceImplementation; 嵌套异常是org.springframework.beans.factory.NoSuchBeanDefinitionException:没有为依赖项找到类型[org.springframework.security.core.userdetails.UserDetailsService]的限定bean:期望至少有一个bean符合此依赖项的autowire候选资格.依赖注释:{@ org.springframework.beans.factory.annotation.Autowired(required = true)}
我用精梳梳理了我的代码,无法查明问题.
Spring Framework版本:3.2.5.RELEASE Spring Security版本:3.2.0.M2
SecurityConfig.java
package com.entirety.app.config;
import com.entirety.app.service.implement.UserDetailsServiceImplementation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import javax.sql.DataSource;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private UserDetailsService userDetailsServiceImplementation;
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(userDetailsServiceImplementation)
.authorizeUrls()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/sec/**").hasRole("MODERATOR")
.antMatchers("/*").permitAll()
.anyRequest().anonymous().and().exceptionHandling().accessDeniedPage("/denied").and() …Run Code Online (Sandbox Code Playgroud) 我需要通过@Autowired注入服务类的具体实现.
服务界面:
public interface PostService {
...
}
Run Code Online (Sandbox Code Playgroud)
执行:
@Service("postServiceImpl")
public class PostServiceImpl implements PostService {
...
}
Run Code Online (Sandbox Code Playgroud)
服务中的方法使用@Transactional注释
现在我想将postServiceImpl注入我的控制器 - 因为我需要使用实现中的一个方法,而不是在接口中:
@Autowired
@Qualifier("postServiceImpl")
private PostServiceImpl postService;
Run Code Online (Sandbox Code Playgroud)
我收到NoSuchBeanDefinitionException并带有以下消息:
没有为依赖项找到类型为[(...).PostServiceImpl]的限定bean:期望至少有一个bean可以作为此依赖项的autowire候选者.
当我将控制器中的字段更改为:
private PostService postService
Run Code Online (Sandbox Code Playgroud)
它工作,但我不能使用PostServiceImpl中的特定方法.
我有一个接口IMenuItem
public interface IMenuItem {
String getIconClass();
void setIconClass(String iconClass);
String getLink();
void setLink(String link);
String getText();
void setText(String text);
}
Run Code Online (Sandbox Code Playgroud)
然后我有这个接口的实现
@Component
@Scope("prototype")
public class MenuItem implements IMenuItem {
private String iconClass;
private String link;
private String text;
public MenuItem(String iconClass, String link, String text) {
this.iconClass = iconClass;
this.link = link;
this.text = text;
}
//setters and getters
}
Run Code Online (Sandbox Code Playgroud)
有没有办法只使用IMenuItem接口从配置类创建多个MenuItem实例?用@autowired还是什么?也可以通过指定构造函数的参数来自动装配?
偶尔我注意到有趣的事情:
我已经实现了spring Converter接口:
@Component
public class MyConverter implements Converter<MyClass1, MyClass2> {
@Override
public MyClass2 convert(MyClass1 source) {
// doesn't matter
}
}
Run Code Online (Sandbox Code Playgroud)
在控制器中,我像这样自动装配它
@Autowire
Converter<MyClass1, MyClass2> myConverter;
Run Code Online (Sandbox Code Playgroud)
惊喜,但春天注入适当的课程.
根据我的信息,spring在运行时自动装配bean.另外我知道在运行时泛型类型擦除.
我试图了解春天的灵魂,但对我来说很难.
你能解释一下春天如何解决这种情况吗?
Symfony 4.2.3
最近从 3.4 版本升级到 4.2.3 并让我的项目工作,但是在 services.yaml 中将 autoconfigure 设置为 true 时,我会收到此错误消息:
Cannot autowire service "App\EventListener\RedirectToLocaleActiveListener": argument "$localeActive" of method "__construct()" has no type-hint, you should configure its value explicitly.
Run Code Online (Sandbox Code Playgroud)
我的服务.yaml
parameters:
locale: de
locale_active: de
app_locales: de|en
uploads_directory_name: uploads
uploads_profile_directory_name: profiles
uploads_directory: '%kernel.root_dir%/../public/%uploads_directory_name%'
profile_directory: '%kernel.root_dir%/../public/%uploads_directory_name%/%uploads_profile_directory_name%'
google_recaptcha_site_key: '%env(GOOGLE_RECAPTCHA_SITE_KEY)%'
services:
_defaults:
autowire: true
autoconfigure: true
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
App\Controller\:
resource: ../src/Controller
tags:
- controller.service_arguments
locales:
class: App\Util\Locales
arguments:
- '%locale_active%'
- '%app_locales%'
- '@session'
app.locale:
class: App\EventListener\LocaleListener
tags: …Run Code Online (Sandbox Code Playgroud) autowired ×10
spring ×9
java ×6
service ×3
annotations ×1
dependencies ×1
generics ×1
interface ×1
proxy ×1
refactoring ×1
spring-mvc ×1
symfony-4.2 ×1
target ×1