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

目录
  • @ComponentScan在spring中无效
    • 查了大量资料之后,找到了原因
  • @Component和@ComponentScan常规理解
    • @Component和@ComponentScan的联系
    • @SpringBootApplication和@ComponentScan,扫描包的区别

@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所在的包。

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

(0)

相关推荐

  • Spring注解开发@Bean和@ComponentScan使用案例

    组件注册 用@Bean来注册 搭建好maven web工程 pom加入spring-context,spring-core等核心依赖 创建实例类com.hjj.bean.Person, 生成getter,setter方法 public class Person { private String name; private int age; } 创建com.hjj.config.MainConfig @Configuration //告诉spring是一个配置类 public class Main

  • 为什么说要慎用SpringBoot @ComponentScan

    目录 场景复现 解密 解决方案 场景复现 为了统一定制一个过滤器(Filter),所以在另外一个工程里面创建了一个过滤器,并通过jar包的方法导入当前项目,通过@ComponentScan({"org.example.config"})指定扫描包路径. 下面的我的启动类: 导入的jar: 问题 预期效果是这样,正常加载 启动后,原来的Swagger目录进去是这样的,原来的Controller全部都没有被加载进来 解密 以为过滤器导致所有路径没有加载,后面百度了解BasicErrorCo

  • springboot @ComponentScan注解原理解析

    这篇文章主要介绍了springboot @ComponentScan注解原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 @ComponentScan 告诉Spring从哪里找到bean. 如果你的其他包都在@SpringBootApplication注解的启动类所在的包及其下级包,则你什么都不用做,SpringBoot会自动帮你把其他包都扫描了. 如果你有一些bean所在的包,不在启动类的包及其下级包,那么你需要手动加上@Compone

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

    目录 @ComponentScan在spring中无效 查了大量资料之后,找到了原因 @Component和@ComponentScan常规理解 @Component和@ComponentScan的联系 @SpringBootApplication和@ComponentScan,扫描包的区别 @ComponentScan在spring中无效 在我实现第一个spring AOP程序的时候,我按照主流的推荐,采用注解@ComponentScan @Aspect @Before 来实现一个切面. 让我

  • Spring中的refresh方法分析

    目录 1 前言 2 源码入口哪里找 3 refresh 核心方法 4 总结 1 前言 在项目开发和面试过程中 spring 都是非常重要的,在前文中已经讲述了Spring BeanFactory 与 FactoryBean 的区别,在后续的文章中将继续更新 Spring 源码心得.了解原理性的一些内容之后就会在应用能够得心应手,在项目开发和面试中,就能很好地 battle 和 show muscle. 2 源码入口哪里找 Spring 的源码阅读,需要找到入口文件,一般情况下在 Spring 项

  • oracle定时任务定时无效的原因分析与解决

    目录 创建oracle定时任务定时任务并没有按时执行 创建定时任务JOB(63)定时任务并没有执行 原因分析: 解决方案: 总结 创建oracle定时任务定时任务并没有按时执行 由于项目需要同步其他系统数据库数据库,在创建完dblink,存储过程后,新建了一个dbm_job任务,满心期待的可以早点下班时,却发现定时任务并没有按照时间执行. 创建定时任务JOB(63)定时任务并没有执行 原因分析: 可能数据库对于JOB的功能并没有开启,于是引着这个方向去寻找解决方法. 解决方案: 通过查阅资料发现

  • ubuntu16.04下vim安装失败的原因分析及解决方案

    先给大家说下问题描述? 重装了ubuntu系统,安装vim出现了以下问题: sudo apt-get install vim 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 有一些软件包无法被安装.如果您用的是 unstable 发行版,这也许是 因为系统无法达到您要求的状态造成的.该版本中可能会有一些您需要的软件 包尚未被创建或是它们已被从新到(Incoming)目录移出. 下列信息可能会对解决问题有所帮助: 下列软件包有未满足的依赖关系: vim :

  • JQuery EasyUI 加载两次url的原因分析及解决方案

    1.传统方式 <span style="font-size:18px;">$(function () { var url = "../Source/Query/jhDataQry.ashx?action=query"; $(dg).datagrid({ url: url, queryParams: { qsrq: qsrq, zzrq: zzrq } }); }) <table id="DataGrid" class="

  • VS Code安装go插件失败原因分析以及解决方案

    目录 问题背景 问题原因 解决方案 方案1:快速方案 方案2:环境变量中配置 方案3:vscode中配置 总结 问题背景 VSCode是我们开发go程序的常用工具,但是安装VSCode成功后,创建一个.go文件会有如下提示: 这个是vscode提示你需要安装go插件,但是当你点击install all进行安装时,发现会安装失败. Installing 8 tools at D:\pragrams\go\bin  gocode  gopkgs  go-outline  go-symbols  dl

  • Vue组件传值过程中丢失数据的分析与解决方案

    前言 在上一篇文章 JavaScript 中的两种数据类型中,分别介绍了基本类型和引用类型,以及引用类型的浅拷贝与深拷贝.这里需要注意的是,该文章中深拷贝引用类型值的方法,并不是完美的,引用类型值中的某些属性值,仍不能完整地复制到新的变量中.比如函数值,在深拷贝过程中,就会丢失. 问题 在实际项目中,假如使用了二次封装的组件,并且封装的组件内部做了一些属性值的深拷贝操作,就有极有可能因为传入的属性值是引用类型的值,导致丢失部分数据. 举例 以基于 el-table 封装的 ak-table 组件

  • redis反序列化报错原因分析以及解决方案

    目录 redis反序列化报错原因分析 序列化id’不一致 实体类属性不一致 redis序列化转换类型报错 总结 redis反序列化报错原因分析 问题:Cannot deserialize,无法反序列化 分析: 序列化id’不一致 1.实体类实现了序列化接口后,没有指定序列化id. 2.读和写的class版本不一致,srpingboot jar包版本不一致的两个class文件,序列化id不一致.因为我们项目是几个系统对接,共享的一个redis库. 实体类属性不一致 可能存到redis的时候是两个属

  • Android中Memory Leak原因分析及解决办法

    在Android开发过程中,我们经常碰到的情况就是在我们不清楚为什么情况下,程序突然出现Crash了.其中有一类日志相信大家都经常碰到过,这类日志就是OOM相关的日志.这类日志除了我们知道的Bitmap操作的时候会经常导致,还有一种隐藏的较深的原因就是内存泄露(Memory Leak). 内存泄露产生原因和影响: 原因:当一个Object不再需要的时候,本该被GC回收时,但是因为另一个正在使用的Object持有它导致不能正常的被回收,本该被回收的对象不能回收,还存留在堆内存中,此时就产生了内存泄

  • Vscode中不再支持JDK8的原因分析及解决方案

    昨天还用得好好的,今天突然给我说仅支持JDK11以上了,也不能进行正常的代码补全了. 看了一下,是Language Support for Java™ by Red Hat这个拓展更新到0.65.0的原因. 因为Eclipse平台决定将JDK11作为9月发布的最低要求,而vscode是依赖eclipsejdt.ls服务器的,所以需要更新到JDK11. 解决方案1 如果不是必须使用JDK8,可以选择更换为JDK11或更新 解决方案2 官方说可以在settings.json中配置java.confi

随机推荐