• spring之通过注解方式配置Bean(二)


    上一节讲到了基本的基于注解的配置Bean,但是每个Bean之间是没有关联的,现在我们想实现下面的功能。

    基本目录:

    UserController.java

    在这里调用UserService中的add方法。

    package com.gong.spring.beans.annotation.controller;
    
    import org.springframework.stereotype.Controller;
    
    import com.gong.spring.beans.annotation.service.UserService;
    
    @Controller
    public class UserController {
        private UserService userService;
        public void execute() {
            System.out.println("UserController的execute方法");
            userService.add();
        }
    }

    UserService.java

    在这里调用UserRepository中的save方法。

    package com.gong.spring.beans.annotation.service;
    
    import org.springframework.stereotype.Service;
    
    import com.gong.spring.beans.annotation.repository.UserRepository;
    
    @Service
    public class UserService {
        private UserRepository userRepository;
        public void add() {
            System.out.println("UserService中的add方法");
            userRepository.save();
        }
    }

    UserRepository.java

    package com.gong.spring.beans.annotation.repository;
    
    public interface UserRepository {
        public void save();
    }

    UserRepositoryImpl.java

    package com.gong.spring.beans.annotation.repository;
    
    import org.springframework.stereotype.Repository;
    
    @Repository(value="userRepository")
    public class UserRepositoryImpl implements UserRepository{
    
        @Override
        public void save() {
            // TODO Auto-generated method stub
            System.out.println("UserReposityImpl的save方法");
        }
    
    }

    Main.java

    package com.gong.spring.beans.annotation;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.gong.spring.beans.annotation.controller.UserController;public class Main {
        public static void main(String[] args) {
            //1.创建spring的IOC容器对象
            ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-annotation.xml");
            //2.从容器中获取Bean实例
            UserController userController = (UserController) ctx.getBean("userController");
            System.out.println(userController);
         userController.execute();
        }
        
    }

    beans-annotation.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:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
            
        <!-- 配置springIOC容器扫描的包 -->    
        <context:component-scan base-package="com.gong.spring.beans.annotation">
        </context:component-scan>
    
    </beans>

    按照上节正常的配置,打印下输出结果:

    会报空指针异常,是因为我们还没有在UserController中装配userService属性。

    组件装配:<context:component-scan> 还会自动注册AutowiredAnnotationBeanPostProcessor实例,该实例可以自动装配具有@Autowired、@Resource和@INject注解的属性。

    使用@Autowired注解自动装配具有类型兼容的单个Bean属性:

    • 构造器:普通字段,即使是非public,一切具有参数的方法都可使用@Autowired注解。
    • 默认情况下,所有使用@Autowired注解的属性都需要被设置。当spring找不到匹配的bean来装配属性时,会抛出异常。若某一属性不允许被设置,可以设置@Autowired注解的required属性为false。
    • 默认情况下,当springIOC容器存在多个类型兼容的Bean时,通过类型的自动装配将无法工作。此时可在@Qualifier注解里提供Bean的名称。spring允许对方法的入参标注@Qualifier以指定注入bean的名称。
    • @Autowired注解也可以应用到数据类型的属性上,此时spring将会把所有匹配的bean进行自动装配。
    • @Autowired注解也可以应用在集合属性上,此时spring会读取集合的类型信息,然后自动装配给所有与之兼容的bean。
    • @Autowired用在jav.util.Map上时,若该Map的键值为string,那么spring将自动装配与Map值类型兼容的bean,此时bean的名称为键值。

    讲了这么多,就是在要用@Autowired让属性自动装配到相应的bean上,即变成:

    @Autowired
    private UserService userService;
    @Autowired
    private UserRepository userRepository;

    那么,就可以正常运行了,输出:

    当然,还有另一种方式就是将@Autowired对setter方法进行注解,而不是属性,即:

        private UserRepository userRepository;
        @Autowired
        public void setUserRepository(UserRepository userRepository) {
            this.userRepository = userRepository;
        }

    这样也是可以的。

    TestObject.java

    package com.gong.spring.beans.annotation;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class TestObject {
    
    }

    接下来我们在userRepositoryImpl中加入:

    package com.gong.spring.beans.annotation.repository;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Repository;
    
    import com.gong.spring.beans.annotation.TestObject;
    
    @Repository(value="userRepository")
    public class UserRepositoryImpl implements UserRepository{
        
        @Autowired
        private TestObject testObject;
    
        @Override
        public void save() {
            // TODO Auto-generated method stub
            System.out.println("UserReposityImpl的save方法");
            System.out.println(testObject);
        }
    
    }

    程序是可以运行的:

    我们将TestObjec.java中的@Component注解去掉:

    警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController': Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through method 'setUserRepository' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userRepository': Unsatisfied dependency expressed through field 'testObject'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.gong.spring.beans.annotation.TestObject' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

    因为我们设置了:

    @Autowired
    private TestObject testObject;

    没有找到该Bean,就会抛出异常。

    我们再加上:说明不必要装配该属性

    @Autowired(required=false)
    private TestObject testObject;

    此时即使没有装配上TestObject也不会抛出异常了,即

    (我们删除掉了@Autowired(required=false)private TestObject testObject;System.out.println(testObject);)我们再新建一个UserJdbcRepository.java

    package com.gong.spring.beans.annotation.repository;
    
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class UserJdbcRepository implements UserRepository {
    
        @Override
        public void save() {
            // TODO Auto-generated method stub
            System.out.println("UserJdbcRepository的save方法");
        }
    
    }

    同时删除掉@Repository(value="userRepository")中的value属性,运行会抛出异常:没有一个唯一的bean

    因此存在多个bean的实现类时,我们需要指定bean的名字,在调用时调用该名字,即:

        private UserRepository userRepository;
        @Autowired
        public void setUserRepository(UserRepository userRepository) {
            this.userRepository = userRepository;
        }

    或者,我们这么指定要装配的bean的名字:

        private UserRepository userRepository;
        @Autowired
        @Qualifier("userJdbcRepository")
        public void setUserRepository(UserRepository userRepository) {
            this.userRepository = userRepository;
        }

    输出:

    也可以将该注解放入的setter方法中:

        private UserRepository userRepository;
        @Autowired
        public void setUserRepository(@Qualifier("userJdbcRepository") UserRepository userRepository) {
            this.userRepository = userRepository;
        }

    @Resource和@Inject和@Autowired类似,一般使用@Autowired就足够了。

  • 相关阅读:
    执行存储过程 /创建存储过程:
    C# 设置本页面内所有TextBox为只读
    js 取得CheckBoxList的选中项的值
    把某些区域定为contentEditable="true"!
    如何在模态对话框中进行提交而不新开窗口?
    屏蔽 按键
    窗口与对话框之间的传值
    input button 的 onserverclick 事件
    checkbox js
    1.showModalDialog返回值给父窗口 2.winow.open开的窗口赋值给父窗口
  • 原文地址:https://www.cnblogs.com/xiximayou/p/12157120.html
Copyright © 2020-2023  润新知