Cause analysis and solution of @ ComponentScan being invalid in spring

  • 2021-12-11 07:30:00
  • OfStack

Directory @ ComponentScan is invalid in spring. After looking up a lot of information, we found the reason @ Component and @ ComponentScan generally understand the connection between @ Component and @ ComponentScan @ SpringBootApplication and @ ComponentScan, scan the difference between packages

@ ComponentScan is not valid in spring

When I implemented the first spring AOP program, I used the annotation @ ComponentScan @ Aspect @ Before to implement a section according to the mainstream recommendation.

What puzzles me for 10 points is. My program has never been able to call the notification correctly. And my notice is no different from the mainstream. The code is as follows:

Notification class, which defines the facet:


package com.bfytech.spring_8_bean3; 
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
 
@Aspect
@Component
public class Advice { 
 @Before("execution(* com.bfytech.spring_8_bean3.Person.getName(..))")
 public void logBeforeFunction() {
  System.out.println("function begin");
 }
 @After("execution(* com.bfytech.spring_8_bean3.Person.*(..))")
 public void logAfterFunction() {
  System.out.println("function end");
 }
}

Business category:


package com.bfytech.spring_8_bean3; 
import org.springframework.stereotype.Component; 
@Component
public class Person {
 private String name;
 private int age;
 public String getName() {
  System.out.println("getName...");
  return name;
 }
 public void setName(String name) {
  this.name = name;
  System.out.println("setName...");
 }
 public int getAge() {
  System.out.println("getAge...");
  return age;
 }
 public void setAge(int age) {
  System.out.println("setAge...");
  this.age = age;
 } 
}

Bean configuration class:


package com.bfytech.spring_8_bean3; 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan

public class BeanConfig { 
 @Bean
 public Advice advice() {
  return new Advice();
 }
}

AppicationContext.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
</beans>

The last call class App


package com.bfytech.spring_8_bean3; 
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );        
        ApplicationContext context = new FileSystemXmlApplicationContext("ApplicationContext.xml");
        Person person = (Person) context.getBean(Person.class);
          person.setName("Tony");
          person.setAge(88);
          System.out.println(person.getName());
          System.out.println(person.getAge());
    }
}

Depressed. After many attempts, it was discovered that the following line was added to ApplicationContext. xml:


<context:component-scan base-package="com.bfytech.spring_8_bean3"></context:component-scan>

After that, AOP can be started normally.

After looking up a lot of information, I found out the reason

It turns out that xml configuration and annotation configuration are confused in 1 in many materials!

The contents of ApplicationContext. xml will take effect when you use the xml configuration. But only if you use FileSystemXmlApplicationContext or ClassPathXmlApplicationContext to read this xml, the configuration will take effect! At the same time @ ComponentScan will be ignored!

When you use annotation configuration, you should use AnnotationConfigApplicationContext to load, and then @ ComponentScan in the configuration class will take effect.

Modify code App. java to


package com.bfytech.spring_8_bean3; 
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );     
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        Person person = (Person) context.getBean(Person.class);         
          person.setName("Tony");
          person.setAge(88);
          System.out.println(person.getName());
          System.out.println(person.getAge());
    }
}

The running result is normal!

By the way, there is another pit. Because execution expressions are not checked at compile time, any punctuation errors are ignored at run time (?? I wonder why no exception is thrown), so they need to be checked over and over again. For example, the following expression, do you think it is wrong?


@Before("execution(* com.bfytech.spring_8_bean3.*.*(**))")

This expression is incorrect because (**) should be (..). And this does not report any errors at run time. But the sliced code will not run......

@ Component and @ ComponentScan General Understanding

Connection between @ Component and @ ComponentScan

The @ Component annotation is used to inject the bean we wrote into the container for use.

The @ ComponentScan annotation scans packages for bean (e.g. Spring doesn't know you defined an bean unless it knows where to find the bean, and what ComponentScan does is tell Spring where to find the bean), and you define which packages need to be scanned.

1 Once you specify, Spring will look for bean in the specified package and its subordinate packages. These two annotations are used together.

@ SpringBootApplication and @ ComponentScan, the difference between scanning packets

If all your other packages are using the @ SpringBootApplication annotated main app package and its subordinate packages, you don't have to do anything, and SpringBoot will automatically scan all other packages for you. If you have a package with bean, a package not in main app and its subordinate packages, you need to manually add @ ComponentScan annotation and specify the package where bean is located.


Related articles: