好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

@ComponentScan在spring中无效

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

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

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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

  }

}

业务类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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

?

1

2

3

4

5

6

7

8

9

10

<? xml version = "1.0" encoding = "UTF-8" ?>

< beans xmlns = "http://HdhCmsTestspringframework.org/schema/beans"

     xmlns:xsi = "http://HdhCmsTestw3.org/2001/XMLSchema-instance"

     xmlns:p = "http://HdhCmsTestspringframework.org/schema/p"

     xmlns:context = "http://HdhCmsTestspringframework.org/schema/context"

     xmlns:util = "http://HdhCmsTestspringframework.org/schema/util"

     xsi:schemaLocation="http://HdhCmsTestspringframework.org/schema/beans http://HdhCmsTestspringframework.org/schema/beans/spring-beans-4.1.xsd

         http://HdhCmsTestspringframework.org/schema/context http://HdhCmsTestspringframework.org/schema/context/spring-context-4.3.xsd

         http://HdhCmsTestspringframework.org/schema/util http://HdhCmsTestspringframework.org/schema/util/spring-util-4.3.xsd">

</ beans >

最后的调用类App

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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中添加如下行:

?

1

< 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为

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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表达式因为没有编译时检查,任何标点符号的错误也会在运行时忽略(??我很纳闷,为什么不抛异常),所以需要反复检查。比如说下面的表达式,你觉得有错么?

?

1

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

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

原文链接:https://blog.csdn.net/CandCplus/article/details/81564513

查看更多关于@ComponentScan在spring中无效的原因分析及解决方案的详细内容...

  阅读:32次