Spring和SSM整合中: context-component和context:annotation-config标签的使用



复习Spring, 正好这两个标签我分的也不是很清, 就写篇文章记录一下.

准备工作:

1.TestController.java:

public class TestController {
    public void test() {
        System.out.println("controller ok");
    }
}

2.TestService.java:

public class TestService {
    TestDao testDao;

    public void setTestDao(TestDao testDao) {
        this.testDao = testDao;
    }

    public void test() {
        System.out.println("service ok");
        testDao.test();
    }
}

3.TestDao.java:

public class TestDao {
    public void test() {
        System.out.println("dao ok");
    }
}

4.Test.java:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        TestController controller = (TestController) context.getBean("testController");
        controller.test();

        TestService service = (TestService) context.getBean("testService");
        service.test();

        TestDao testDao = (TestDao) context.getBean("testDao");
        testDao.test();
    }
}

5.applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <bean id="testController" class="com.ld.controller.TestController"></bean>					
					
  <bean id="testService" class="com.ld.service.TestService">
      <property name="testDao" ref="testDao"/>
  </bean>
<bean id="testDao" class="com.ld.dao.TestDao"></bean></beans>

---------------------------------------------  假装是条分割线  ---------------------------------------------------------

● 我在配置文件中配置了3个bean,并且为TestService注入了testDao属性.

此时Test类的main方法可以正常运行,不会报错, 结果如下:

controller ok
service ok
dao ok
dao ok

● 若我想使用@Autowired注解将TestDao注入到TestService中, 则需要context:annotation-config这个标签来启用注解功能.

修改TestService类和配置文件:

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <context:annotation-config></context:annotation-config>

    <bean id="testController" class="com.ld.controller.TestController"></bean>

    <bean id="testService" class="com.ld.service.TestService"></bean>

    <bean id="testDao" class="com.ld.dao.TestDao"></bean>

</beans>

TestService.java:

public class TestService {
    @Autowired
    TestDao testDao;

    public void test() {
        System.out.println("service ok");
        testDao.test();
    }
}

运行Test的main方法, 结果不变:

controller ok
service ok
dao ok
dao ok

● 若我想自动注册bean,而不是在xml文件中使用bean标签来注册, 首先想到的是在被注册类上使用@Component注解,但这里模拟了controller层,service层和dao层, 所以分别使用@Controller, @Service, @Repository注解:

配置文件修改为:

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<context:annotation-config></context:annotation-config>

</beans>

TestController.java:

@Controller
public class TestController {
    public void test() {
        System.out.println("controller ok");
    }
}

TestService.java:

@Service
public class TestService {
    @Autowired
    TestDao testDao;

    public void test() {
        System.out.println("service ok");
        testDao.test();
    }
}

TestDao.java:

@Repository
public class TestDao {
    public void test() {
        System.out.println("dao ok");
    }
}

现在运行一下,会发现报错了:

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'testController' is defined
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1168)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:281)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:956)
	at com.ld.test.Test.main(Test.java:16)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

根据描述,报错信息为没有名为:"testController"的bean被定义, 其实包括service和dao的bean都没有被定义,只不过我们先调用了testController的test方法,所以在找不到testController后程序就终止了,所以没有打印出相应的错误信息.

● 那为什么会出现这样的异常呢? 我们明明启用了注解功能啊.

原来context:annotation-config标签的作用是只在开始了已被注册的bean上的注解功能, 也就是说之所以我们使用@Autowired注解能将testDao成功注入,是因为我们在配置文件中已经使用bean标签注册了那3个bean. 遇到未注册的bean上的注解,这个标签也无能为力, 它不能将标注了@Component,@Controller等注解的类注册为bean.

那该怎么办呢? 这是时候就该使用context:component-scan标签了.

● context:component-scan标签不仅可以识别@Autowired等注解, 还能将被@Component等注解标注的类注册到Spring的IOC容器中, 成为可供使用的bean.   该标签有一个base-package属性, 用来指定要扫描的包的包名.

修改配置文件:

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd">

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

</beans>

运行结果:

controller ok
service ok
dao ok
dao ok

结果正确.


在SSM整合中的使用



大家都知道Spring和SpringMVC一起使用时, Spring容器包含了SpringMVC容器, 可称为Spring容器为父容器,SpringMVC容器为子容器. 



   我们在applicationContext.xml(SSM整合后一般叫做spring-mybatis.xml)中使用context:component-scan标签, base-package应该指定为除controller包以外的包,因为这样就不会把Controller也注册到Spring容器中. 我们通常会在spring-mvc.xml中也配置一个context:component-scan标签, base-package只指定为controller包,  只将controller注册到SpringMVC容器中. 

● 想了解上述细节请看这篇文章:  https://blog.csdn.net/s740556472/article/details/54879954

那么问题来了, 在spring的配置文件中,base-package该怎么配置呢? 难道要service,dao等包各对应一个context:component-scan标签吗?  这会显得配置文件非常臃肿. Spring当然考虑到了这一点, 提供了它的子标签:<context:include-filter/>和<context:exclude-filter/>, 顾名思义, 就是引入过滤器和排除过滤器.使用如下:

<context:component-scan base-package="com.ld">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>




在spring的配置文件中, 只需要使用exclude-filter标签, 将过滤类型设置为annotation(注解), 将expression配置为Controller注解的全名即可实现过滤.


在使用<context:include-filter/>标签时需要注意, 如果你只想扫描几个包,剩下的过滤掉,这样写是不行的:

<context:component-scan base-package="com.ld">
    <context:include-filter type="annotation"
                            expression="org.springframework.stereotype.Service" />
    <context:include-filter type="annotation"
                            expression="org.springframework.stereotype.Repository" />
</context:component-scan>

尽管你使用了两个include-filter标签, 但实际上还是将"com.ld"下所有的包扫描了, 这时候需要指定context:component标签的另一个属性: use-default-filter, 将其指定为false即可.

● 具体解析请看这篇文章: https://blog.csdn.net/m0_37965853/article/details/72898490


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值