春天在一个注入的依赖项需要同一类中的一个bean时,没有填充其他变量。

huangapple go评论74阅读模式
英文:

Spring is not filling other variables when one injected dependency requires a bean in the same class

问题

以下是翻译好的部分:

@Configuration
public class BeansConfig {

    @Autowired
    private Config config; //Only values of a config file

    @Autowired
    private JDAListener listener;

    @Autowired
    private PermissionProvider permissionProvider;
    @Autowired
    private LanguageProvider languageProvider;
    @Autowired
    private PrefixProvider prefixProvider;
    @Autowired
    private HelpProvider helpProvider;

    @Bean
    public ShardManager shardManager() throws LoginException, IllegalArgumentException {
        DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(this.config.getBotToken())
                .enableIntents(GatewayIntent.GUILD_MEMBERS)
                .setMemberCachePolicy(MemberCachePolicy.ALL)
                .setStatus(OnlineStatus.IDLE)
                .setShardsTotal(this.config.getTotalShards())
                .addEventListeners(Arrays.asList(this.listener));

        ShardManager manager = builder.build();
        this.commandFramework().setShardManager(manager);

        return manager;
    }

    @Bean
    public CommandFramework commandFramework() {
        LogManager.getLogger().error("HelpProvider name: " + this.helpProvider.getClass().getCanonicalName());
        return new FrameworkBuilder()
                .addOwners(Arrays.stream(this.config.getOwnerIds()).filter(ownerId -> ownerId.matches("^(\\d)+$")).map(ownerId -> Long.parseLong(ownerId)).collect(Collectors.toList()))
                .setLogger(NightBot.logger())
                .allowBots(false)
                .allowDM(false)
                .allowMention(true)
                .allowRainbowColors(true)
                .withPrefixProvider(this.prefixProvider)
                .withLanguageProvider(this.languageProvider)
                .withPermissionProvider(this.permissionProvider)
                .withHelpProvider(this.helpProvider)
                .withCustomArgumentProcessor(new NamedArgumentProcessor())
                .registerClientLater()
                .build();
    }
}

此外,您提到的关于 Spring Bean 依赖注入和创建顺序的问题,由于该问题涉及到特定的 Spring 上下文、依赖解析和循环依赖等复杂情况,我无法提供详细的解决方案。通常情况下,Spring 容器会尽力解决循环依赖问题,但是有时候复杂的依赖关系可能导致创建顺序的困扰。如果您的代码确实没有循环依赖,但仍然遇到问题,您可能需要对 Spring 的配置和依赖关系进行深入分析以找到解决方案。

英文:

So, I have the following class:

@Configuration
public class BeansConfig {
@Autowired
private Config config; //Only values of a config file
@Autowired
private JDAListener listener;
@Autowired
private PermissionProvider permissionProvider;
@Autowired
private LanguageProvider languageProvider;
@Autowired
private PrefixProvider prefixProvider;
@Autowired
private HelpProvider helpProvider;
@Bean
public ShardManager shardManager() throws LoginException, IllegalArgumentException {
DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(this.config.getBotToken())
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.setMemberCachePolicy(MemberCachePolicy.ALL)
.setStatus(OnlineStatus.IDLE)
.setShardsTotal(this.config.getTotalShards())
.addEventListeners(Arrays.asList(this.listener));
ShardManager manager = builder.build();
this.commandFramework().setShardManager(manager);
return manager;
}
@Bean
public CommandFramework commandFramework() {
LogManager.getLogger().error("HelpProvider name: " + this.helpProvider.getClass().getCanonicalName());
return new FrameworkBuilder()
.addOwners(Arrays.stream(this.config.getOwnerIds()).filter(ownerId -> ownerId.matches("^(\\d)+$")).map(ownerId -> Long.parseLong(ownerId)).collect(Collectors.toList()))
.setLogger(NightBot.logger())
.allowBots(false)
.allowDM(false)
.allowMention(true)
.allowRainbowColors(true)
.withPrefixProvider(this.prefixProvider)
.withLanguageProvider(this.languageProvider)
.withPermissionProvider(this.permissionProvider)
.withHelpProvider(this.helpProvider)
.withCustomArgumentProcessor(new NamedArgumentProcessor())
.registerClientLater()
.build();
}
}

When I try to use this class it fails because of a possible circular reference. I checked the code and found out that all is okay and there should be no circular reference. So I tried out and detected that when the Bean commandFramework is in creation, the injected variables are all null, because of the JDA Listener requiring the CommandFramework as dependency. When the command framework was created with the null values, all works, the Shard Manager can be created with the jda listener and all the other variables then available. So my question is, why does Spring not first inject the providers, then creates the CommandFramework bean, as it requires them, then injects the JDA Listener with the CommandFramework dependency and then at last creates the shard manager? Why is it required that all variables are created so that the bean can be created? Why does it not try to create that bean first before injecting JDAListener.

The Stacktrace

As asked, here the stacktrace:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'beansConfig': Unsatisfied dependency expressed through field 'listener'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'JDAListener': Unsatisfied dependency expressed through field 'cf'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'commandFramework' defined in class path resource [dev/teamnight/nightbot/BeansConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [dev.teamnight.command.CommandFramework]: Circular reference involving containing bean 'beansConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'commandFramework' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:895) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
at dev.teamnight.nightbot.NightBotApplication.main(NightBotApplication.java:53) ~[classes/:na]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'JDAListener': Unsatisfied dependency expressed through field 'cf'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'commandFramework' defined in class path resource [dev/teamnight/nightbot/BeansConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [dev.teamnight.command.CommandFramework]: Circular reference involving containing bean 'beansConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'commandFramework' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1306) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
... 18 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'commandFramework' defined in class path resource [dev/teamnight/nightbot/BeansConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [dev.teamnight.command.CommandFramework]: Circular reference involving containing bean 'beansConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'commandFramework' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:484) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1306) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
... 31 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [dev.teamnight.command.CommandFramework]: Circular reference involving containing bean 'beansConfig' - consider declaring the factory method as static for independence from its containing instance. Factory method 'commandFramework' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
... 44 common frames omitted
Caused by: java.lang.NullPointerException: null
at dev.teamnight.nightbot.BeansConfig.commandFramework(BeansConfig.java:65) ~[classes/:na]
at dev.teamnight.nightbot.BeansConfig$$EnhancerBySpringCGLIB$$fea6c58e.CGLIB$commandFramework$1(<generated>) ~[classes/:na]
at dev.teamnight.nightbot.BeansConfig$$EnhancerBySpringCGLIB$$fea6c58e$$FastClassBySpringCGLIB$$3b1aec1a.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at dev.teamnight.nightbot.BeansConfig$$EnhancerBySpringCGLIB$$fea6c58e.commandFramework(<generated>) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
... 45 common frames omitted

The Stacktrace says that the helpProvider and that is caused because the BeansConfig class members weren't filled with the specificed providers. But the providers are independent from CommandFramework and ShardManager, so they should be injected.

Why does spring not do this in this order:

  1. Try to inject all variables, JDAListener fails, but the providers are injected, JDAListener requires a bean commandFramework
  2. Create the bean with the name commandFramework
  3. Try again to create JDAListener, now it succeeds
  4. Create the bean with name ShardManager

答案1

得分: 0

对于所有遇到相同问题的人,这是我的解决方案。

我随机找到了一些代码片段,尝试并修复了我的问题。我移除了需要CommandFramework bean的@Autowired private JDAListener listener,并将其作为ShardManager的方法参数。现在可以创建BeansConfig对象,并且这些bean也成功地被创建了:

@Configuration
public class BeansConfig {
	
	@Autowired
	private Config config;
	
	@Autowired
	private PermissionProvider permissionProvider;
	@Autowired
	private LanguageProvider languageProvider;
	@Autowired
	private PrefixProvider prefixProvider;
	@Autowired
	private HelpProvider helpProvider;
	
	@Bean
	public ShardManager shardManager(JDAListener listener) throws LoginException, IllegalArgumentException {
		DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(this.config.getBotToken())
				.enableIntents(GatewayIntent.GUILD_MEMBERS)
				.setMemberCachePolicy(MemberCachePolicy.ALL)
				.setStatus(OnlineStatus.IDLE)
				.setShardsTotal(this.config.getTotalShards())
				.addEventListeners(Arrays.asList(listener));
		
		ShardManager manager = builder.build();
		this.commandFramework().setShardManager(manager);
		
		return manager;
	}
	
	@Bean
	public CommandFramework commandFramework() {
		LogManager.getLogger().error("HelpProvider name: " + this.helpProvider.getClass().getCanonicalName());
		return new FrameworkBuilder()
				.addOwners(Arrays.stream(this.config.getOwnerIds()).filter(ownerId -> ownerId.matches("^(\\d)+$")).map(ownerId -> Long.parseLong(ownerId)).collect(Collectors.toList()))
				.setLogger(NightBot.logger())
				.allowBots(false)
				.allowDM(false)
				.allowMention(true)
				.allowRainbowColors(true)
				.withPrefixProvider(this.prefixProvider)
				.withLanguageProvider(this.languageProvider)
				.withPermissionProvider(this.permissionProvider)
				.withHelpProvider(this.helpProvider)
				.withCustomArgumentProcessor(new NamedArgumentProcessor())
				.registerClientLater()
				.build();
	}
}
英文:

For everyone who comes up with the same problem, here is my solution.

I randomly found some piece of code which I tried out and fixed my problem. I removed the @Autowired private JDAListener listener which required the CommandFramework bean and put it as method paramter for the ShardManager. Now the BeansConfig object can be created and the beans are also created successfully:

@Configuration
public class BeansConfig {
	
	@Autowired
	private Config config;
	
	@Autowired
	private PermissionProvider permissionProvider;
	@Autowired
	private LanguageProvider languageProvider;
	@Autowired
	private PrefixProvider prefixProvider;
	@Autowired
	private HelpProvider helpProvider;
	
	@Bean
	public ShardManager shardManager(JDAListener listener) throws LoginException, IllegalArgumentException {
		DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(this.config.getBotToken())
				.enableIntents(GatewayIntent.GUILD_MEMBERS)
				.setMemberCachePolicy(MemberCachePolicy.ALL)
				.setStatus(OnlineStatus.IDLE)
				.setShardsTotal(this.config.getTotalShards())
				.addEventListeners(Arrays.asList(listener));
		
		ShardManager manager = builder.build();
		this.commandFramework().setShardManager(manager);
		
		return manager;
	}
	
	@Bean
	public CommandFramework commandFramework() {
		LogManager.getLogger().error("HelpProvider name: " + this.helpProvider.getClass().getCanonicalName());
		return new FrameworkBuilder()
				.addOwners(Arrays.stream(this.config.getOwnerIds()).filter(ownerId -> ownerId.matches("^(\\d)+$")).map(ownerId -> Long.parseLong(ownerId)).collect(Collectors.toList()))
				.setLogger(NightBot.logger())
				.allowBots(false)
				.allowDM(false)
				.allowMention(true)
				.allowRainbowColors(true)
				.withPrefixProvider(this.prefixProvider)
				.withLanguageProvider(this.languageProvider)
				.withPermissionProvider(this.permissionProvider)
				.withHelpProvider(this.helpProvider)
				.withCustomArgumentProcessor(new NamedArgumentProcessor())
				.registerClientLater()
				.build();
	}
}


huangapple
  • 本文由 发表于 2020年8月25日 02:42:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/63566906.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定