@ComponentScan在spring中无效的原因分析及解决方案

 更新时间:2021年11月05日 14:47:15   作者:CandCplus  
这篇文章主要介绍了@ComponentScan在spring中无效的原因分析及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

@ComponentScan在spring中无效

在我实现第一个spring AOP程序的时候,我按照主流的推荐,采用注解@ComponentScan @Aspect @Before 来实现一个切面。

让我十分纳闷的是。 我的程序始终无法正确调用到通知。而且我的通知和主流的毫无差别。代码如下:

通知类,其中定义了切面:

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");
 }
}

业务类:

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配置类:

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>

最后的调用类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());
    }
}

郁闷之余。做了大量尝试,后来发现在ApplicationContext.xml中添加如下行:

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

之后可以正常把AOP启动起来。

查了大量资料之后,找到了原因

原来很多资料中把xml配置和注解配置混淆在一起了!

当你采用xml配置的时候,则ApplicationContext.xml的内容会生效。但是前提是你需要采用FileSystemXmlApplicationContext或者ClassPathXmlApplicationContext去读取这个xml,配置才会生效!同时@ComponentScan会被忽略!

而当你采用注解配置的时候,则你应该使用AnnotationConfigApplicationContext来加载,这时配置类的中的@ComponentScan就会生效。

修改代码App.java为

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());
    }
}

运行结果正常了!

顺便说,还有一个坑。execution表达式因为没有编译时检查,任何标点符号的错误也会在运行时忽略(??我很纳闷,为什么不抛异常),所以需要反复检查。比如说下面的表达式,你觉得有错么?

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

这个表达式是错误的,因为(**)应该是(..).而运行时这个不会报任何错误。但是切片的代码不会运行.....

@Component和@ComponentScan常规理解

@Component和@ComponentScan的联系

@Component 这个注解的作用是把我们写的bean注入到容器中,以供使用。

@ComponentScan 注解的作用则是扫描包中的bean(比如:Spring不知道你定义了某个bean除非它知道从哪里可以找到这个bean,ComponentScan做的事情就是告诉Spring从哪里找到bean),由你来定义哪些包需要被扫描。

一旦你指定了,Spring将会将在被指定的包及其下级包中寻找bean,这两个注解进行配合使用。

@SpringBootApplication和@ComponentScan,扫描包的区别

如果你的其他包都在使用了@SpringBootApplication注解的main app所在的包及其下级包,则你什么都不用做,SpringBoot会自动帮你把其他包都扫描了如果你有一些bean所在的包,不在main app的包及其下级包,那么你需要手动加上@ComponentScan注解并指定那个bean所在的包。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Spring Security灵活的PasswordEncoder加密方式解析

    Spring Security灵活的PasswordEncoder加密方式解析

    这篇文章主要介绍了Spring Security灵活的PasswordEncoder加密方式解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • SpringBoot使用GraphQL开发Web API实现方案示例讲解

    SpringBoot使用GraphQL开发Web API实现方案示例讲解

    这篇文章主要介绍了SpringBoot使用GraphQL开发Web API实现方案,GraphQL是一个从服务端检数据的查询语言。某种程度上,是REST、SOAP、或者gRPC的替代品
    2023-04-04
  • SpringBoot中的multipartResolver上传文件配置

    SpringBoot中的multipartResolver上传文件配置

    这篇文章主要介绍了SpringBoot中的multipartResolver上传文件配置,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 关于Springboot的日志配置

    关于Springboot的日志配置

    Spring Boot默认使用LogBack日志系统,如果不需要更改为其他日志系统如Log4j2等,则无需多余的配置,LogBack默认将日志打印到控制台上,需要的朋友可以参考下
    2023-05-05
  • Java读写锁ReadWriteLock的创建使用及测试分析示例详解

    Java读写锁ReadWriteLock的创建使用及测试分析示例详解

    这篇文章主要为大家介绍了Java读写锁ReadWriteLock的创建使用及测试分析示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • spring boot自定义404错误信息的方法示例

    spring boot自定义404错误信息的方法示例

    这篇文章主要介绍了spring boot自定义404错误信息的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2017-09-09
  • Spring实战之使用p:命名空间简化配置操作示例

    Spring实战之使用p:命名空间简化配置操作示例

    这篇文章主要介绍了Spring实战之使用p:命名空间简化配置操作,结合实例形式分析了spring p:命名空间简单配置与使用操作技巧,需要的朋友可以参考下
    2019-12-12
  • java面试题解LeetCode27二叉树的镜像实例

    java面试题解LeetCode27二叉树的镜像实例

    这篇文章主要为大家介绍了java面试题解LeetCode27二叉树的镜像实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • MySql多表查询 事务及DCL

    MySql多表查询 事务及DCL

    这篇文章主要介绍了MySql多表查询 、事务、DCL的相关资料,需要的朋友可以参考下面文章内容
    2021-09-09
  • Scala递归函数调用自身

    Scala递归函数调用自身

    这篇文章主要介绍了Scala递归函数,Scala递归函数是一种函数可以调用自身的函数,直到满足某个特定的条件为止。在函数式编程的语言中,递归函数起着重要的作用,因为它可以用来表示循环或迭代的逻辑
    2023-04-04

最新评论