web-dev-qa-db-fra.com

org.Apache.catalina.core.StandardContext.startInternal Un ou plusieurs écouteurs n'ont pas pu démarrer

Je travaille sur un Java/Spring/ Apache Cxf application web et tout à coup, je reçois l'erreur pendant que j'effectuais des changements apparemment naïfs,

25-Aug-2017 11:48:43.036 INFO [RMI TCP Connection(2)-127.0.0.1] org.Apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
log4j:WARN No appenders could be found for logger (org.Apache.cxf.common.logging.LogUtils).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.Apache.org/log4j/1.2/faq.html#noconfig for more info.
25-Aug-2017 11:48:43.540 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.Apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
25-Aug-2017 11:48:43.554 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.Apache.catalina.core.StandardContext.startInternal Context [] startup failed due to previous errors
[2017-08-25 11:48:43,586] Artifact jaxrs-tutorials:war exploded: Error during artifact deployment. See server log for details.
25-Aug-2017 11:48:49.258 INFO [localhost-startStop-1] org.Apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/Applications/Tomcat-8.5.16/webapps/manager]
25-Aug-2017 11:48:49.310 INFO [localhost-startStop-1] org.Apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Applications/Tomcat-8.5.16/webapps/manager] has finished in [51] ms

Je suppose que c'est le principal info de l'erreur,

25-Aug-2017 11:48:43.540 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.Apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
25-Aug-2017 11:48:43.554 SEVERE [RMI TCP Connection(2)-127.0.0.1] org.Apache.catalina.core.StandardContext.startInternal Context [] startup failed due to previous errors

La structure du projet est fournie,

enter image description here

Le répertoire config est utilisé pour le Java annotation based config et le code est fourni ci-dessous.

Le fichier AppConfig,

@Configuration
@ComponentScan(AppConfig.SERVICE_PACKAGE)
public class AppConfig {

    public static final String BASE_PACKAGE = "mobi.puut";
    public static final String SERVICE_PACKAGE = BASE_PACKAGE + ".services";
    private static final String RESOURCES_PACKAGE = BASE_PACKAGE + ".rest";
    private static final String PROVIDER_PACKAGE = BASE_PACKAGE + ".rest.provider";

    public static final String API_BASE = "/api/*";

    @ApplicationPath("/")
    public class JaxRsApiApplication extends Application {
    }

    @Bean(destroyMethod = "shutdown")
    public SpringBus cxf() {
        return new SpringBus();
    }

    @Bean
    @DependsOn("cxf")
    public Server jaxRsServer(ApplicationContext appContext) {
        JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint(jaxRsApiApplication(), JAXRSServerFactoryBean.class);
        factory.setServiceBeans(restServiceList(appContext));
        factory.setAddress("/" + factory.getAddress());
        factory.setProviders(restProviderList(appContext, jsonProvider()));
        return factory.create();
    }

    @Bean
    public JaxRsApiApplication jaxRsApiApplication() {
        return new JaxRsApiApplication();
    }

    @Bean
    public JacksonJsonProvider jsonProvider() {
        return new JacksonJsonProvider();
    }

    private List<Object> restServiceList(ApplicationContext appContext) {
        return RestServiceBeanScanner.scan(appContext, AppConfig.RESOURCES_PACKAGE);
    }

    private List<Object> restProviderList(final ApplicationContext appContext,
                                          final JacksonJsonProvider jsonProvider) {
        final List<Object> providers = RestProviderBeanScanner.scan(appContext, PROVIDER_PACKAGE);
        providers.add(jsonProvider);
        return providers;
    }

}

WebInitializer est fourni,

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.addListener(new ContextLoaderListener(createWebAppContext()));
        addApacheCxfServlet(servletContext);
    }

    private void addApacheCxfServlet(ServletContext servletContext) {
        CXFServlet cxfServlet = new CXFServlet();

        ServletRegistration.Dynamic appServlet = servletContext.addServlet("CXFServlet", cxfServlet);
        appServlet.setLoadOnStartup(1);

        Set<String> mappingConflicts = appServlet.addMapping(AppConfig.API_BASE);
    }

    private WebApplicationContext createWebAppContext() {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
        appContext.register(AppConfig.class);
        return appContext;
    }

}

J'ai vu les questions similaires à la plate-forme et celles-ci ne m'aident pas et j'ai si peu d'informations pour résoudre le problème.

Comment puis-je utiliser logger pour obtenir plus d'informations et où dois-je les utiliser? De plus, tout aperçu sur la résolution du problème sera utile. J'ai mis à jour les fichiers JAR avec mvn clean install et mvn idea:idea commandes.

UPDATE

Tomcat Localhost Log

enter image description here

Tomcat Catalina Log

enter image description here

6

Je voudrais écrire une réponse détaillée sur le problème et les étapes que j'ai suivies pour résoudre le problème.

A. Il n'y avait pas assez d'informations de journalisation. J'ai recherché le POM et l'ai trouvé,

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

J'ai exclu la journalisation en faveur de SLF4J et je viens de supprimer la balise XML d'exclusion pour obtenir plus d'informations de journalisation. Donc ça devient comme ça,

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

B. Maintenant, je reçois les informations de journalisation. J'ai ce message d'erreur comme,

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'userService' for bean class [mobi.puut.services.UserServiceImpl] conflicts with existing, non-compatible bean definition of same name and class [mobi.puut.services.UserService2Impl]

Vous obtenez le ConflictingBeanDefinitionException pour créer le bean avec le même nom. Bien que j'ai une certaine expérience avec le Spring, je dois créer avec un projet avec le Apache Cxf et, par conséquent, clonez un projet de démonstration dans le même but. Ils ont la même entité User et la même definition - interface et même implementation de cela. Bien que j'aie refactored à toutes les classes du projet et qu'il n'y ait aucune erreur apparente, je garde toujours un problème - je garde le même nom de bean "userService dans 2 implémentations de l'interface.

Le User2 classe dans les entités,

public class User2 {

    private Integer id;
    private String name;

    public User2() {
    }

    public User2(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return String.format("{id=%s,name=%s}", id, name);
    }
}

La classe User dans les entités,

@Entity
@Table(name = "users")
public class User {

    @Id
    @Column
    @NotNull
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @NotNull
    @Column(name = "name")
    @Size(min = 5, max = 45, message = "Name must be between 5 and 45 characters.")
    private String name;

    public User() {

    }

    public User(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public User(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;

        User user = (User) o;

        if (getId() != user.getId()) return false;
        return getName().equals(user.getName());
    }

    @Override
    public int hashCode() {
        int result = getId();
        result = 31 * result + getName().hashCode();
        return result;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

Les interfaces dans les répertoires services,

public interface IUserService2 {

    Collection<User2> getUsers();

    User2 getUser(Integer id);

    Response add(User2 user);
}



public interface IUserService {

    List<User> getCurrentStatuses();

    void create(User user);

    List<User> getAllUsers();
}

Les implémentations des interfaces à l'intérieur du répertoire services,

@Service("userService")
public class UserService2Impl implements IUserService2 {

    private static Map<Integer, User2> users = new HashMap<Integer, User2>();

    static {
        users.put(1, new User2(1, "foo"));
        users.put(2, new User2(2, "bar"));
        users.put(3, new User2(3, "baz"));
    }

    public UserService2Impl() {
    }

    @Override
    public Collection<User2> getUsers() {
        return users.values();
    }

    @Override
    public User2 getUser(Integer id) {
        return users.get(id);
    }

    @Override
    public Response add(User2 user) {
        user.setId(users.size()+1);
        users.put(user.getId(), user);

        //do more stuff to add user to the system..
        return Response.status(Response.Status.OK).build();
    }

}


@Service("userService")
public class UserServiceImpl implements IUserService {

    @Autowired
    @Qualifier("userDao")
    public IUserDao userDao;

    public List<User> getCurrentStatuses() {
        return userDao.getAllUsers();
    }

    public void create(User user) {
        userDao.saveOrUpdate(user);
    }

    public List<User> getAllUsers() {
        List<User> users = userDao.getAllUsers();

        if (Objects.isNull(users)) {
            return null;
        }
        return users;
    }
}

Et, il y avait le error - J'ai annoté 2 classes avec le même nom de bean "userService". J'ai dû le changer comme ça pour donner au bean un nom différent,

@Service("user2Service")
public class UserService2Impl implements IUserService2 {

    // some code
}

Et, cette erreur disparaît. En bref, l'erreur ConflictingBeanDefinitionException due aux 2 beans du même nom et je devais juste fournir un nom différent.

C. J'avais encore des choses à régler. Ensuite, lorsque j'exécute le programme, j'obtiens

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'mobi.puut.database.IUserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=userDao)}


// some consequent error messages not necessay to solve the issue

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'mobi.puut.database.IUserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=userDao)}

L'erreur ici est UnsatisfiedDependencyException et indique qu'il ne peut pas créer un bean avec le nom de userService. OK, c'est le code que j'avais et intégré au projet. La dépendance non satisfaite exprimée à travers le champ à savoir userDao. userDao est l'instance de l'interface de IUserDao et c'était @autowired comme ça,

    @Autowired
    public IUserDao userDao;

Voici plus d'informations sur le code,

@Service("userService")
public class UserServiceImpl implements IUserService {

    @Autowired
    public IUserDao userDao;


     public List<User> getCurrentStatuses() {
        return userDao.getAllUsers();
    }

    public void create(User user) {
        userDao.saveOrUpdate(user);
    }

    public List<User> getAllUsers() {
        List<User> users = userDao.getAllUsers();

        if (Objects.isNull(users)) {
            return null;
        }
        return users;
    }
}

J'ai une interface dans le répertoire database et l'implémentation conséquente de l'interface pour l'utilisateur. Le nom de l'interface est IUserDao et ressemble

soemthing like this, 


public interface IUserDao {

    boolean create(User user);

    void saveOrUpdate(User user);

    boolean create(List<User> users);

    List<User> getAllUsers();

    User getById(int id);
}

Et, la mise en œuvre,

@Repository("userDao")
public class UserDaoImpl implements IUserDao {

    @Autowired
    private SessionFactory sessionFactory;

    // the HQL queries

}

La partie conséquente du message d'erreur était NoSuchBeanDefinitionException et l'application ne trouve pas de bean qualifiant du type (classe) de IUserDao. J'ai toutes les requêtes HQL dans l'implémentation de IUserDao et le code fonctionne parfaitement avant.

Je dois prendre un moment pour réfléchir et enfin, j'ai une intuition qui peut être que la couche database est NOT intégrée à l'application. Voici le configuration que j'ai utilisé,

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.addListener(new ContextLoaderListener(createWebAppContext()));
        addApacheCxfServlet(servletContext);
    }

    private void addApacheCxfServlet(ServletContext servletContext) {
        CXFServlet cxfServlet = new CXFServlet();

        ServletRegistration.Dynamic appServlet = servletContext.addServlet("CXFServlet", cxfServlet);
        appServlet.setLoadOnStartup(1);

        Set<String> mappingConflicts = appServlet.addMapping(AppConfig.API_BASE);
    }

    private WebApplicationContext createWebAppContext() {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();

        // register all the config classes here
        appContext.register(AppConfig.class);
        return appContext;
    }

}

Évidemment, le code no database est intégré dans le WebInitializer. J'ai écrit une nouvelle classe qui fournit toutes les informations du database connection et le hibernate integration et ressemble,

@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan(basePackages = {"mobi.puut.database"})
public class DatabaseConfig {

    @Bean
    public LocalSessionFactoryBean sessionFactory() {

        //  mobi.puut.entities
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(
                new String[]{"mobi.puut.entities"});
        sessionFactory.setHibernateProperties(hibernateProperties());

        return sessionFactory;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(
            SessionFactory sessionFactory) {

        HibernateTransactionManager txManager
                = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);

        return txManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Bean
    public DataSource dataSource() {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");

        // dataSource.setUrl("jdbc:mysql://localhost:3306/wallet?createDatabaseIfNotExist=true");
        dataSource.setUrl("jdbc:mysql://localhost:3306/Wallet");
        dataSource.setUsername("testuser");
        dataSource.setPassword("testpassword");

        return dataSource;
    }

    Properties hibernateProperties() {

        Properties properties = new Properties();
//        properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        return properties;
    }
}

Et puis enfin intégrer dans le WebInitializer. Ceci est le code que j'ai utilisé pour registered la configuration plus tôt dans le WebInitializer,

appContext.register(AppConfig.class);

Mise à jour de la ligne avec le,

appContext.register(AppConfig.class, DatabaseConfig.class);

Enfin, tout fonctionne bien. Ainsi, le répertoire config ressemble,

enter image description here

SUMMERY

J'ai dû résoudre ce problème grâce aux 3 erreurs,

i. ConflictingBeanDefinitionException
ii. UnsatisfiedDependencyException
iii. NoSuchBeanDefinitionException

ConflictingBeanDefinitionException -> 2 beans portant le même nom

UnsatisfiedDependencyException -> Ayez un bean (= "userDao") dans la classe qui n'était pas correcte à utiliser

NoSuchBeanDefinitionException -> le code était correct mais il fallait ajouter la couche de base de données dans le congig pour que le Spring IoC trouve le bean.

J'espère sincèrement que cela aidera certaines personnes.

6