• Spring(1):控制反转和依赖注入、Spring注解的使用


    一、依赖注入DI 与 控制反转IOC
    1、实例化对象方面,Spring和传统模式的区别
    • 传统的方式: 通过new 关键字主动创建一个对象
    • Spring方式:对象的生命周期由Spring来管理,在加载类的时候由Spring容器统一创建类的实例,使用实例的时候,直接从Spring容器中去获取该类的实例对象。IOC是反转控制(Inversion Of Control)的缩写,就像控制权从本来在自己手里,交给了Spring。 
     
    2、定义控制反转的Bean类的两种方式
        (1)在Bean配置文件中,通过配置<bean>节点来配置
    <!-- 在xml文件中,配置bean -->
    <bean id="person" class="com.newbie.domain.Person">
        <property name="name" value="荆小六"/>
    </bean>
    public class Person {
        private String name;
     
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
      
    }
     
    (2)通过注解的方式,来配置Bean
    步骤一:使用注解的方式,配置bean
    <!-- 使用注解的方式,配置bean-->
    <!—- 在Bean配置文件中(如:applicationContext.xml),增加自动扫描组件的配置 —>
    <context:annotation-config/>
    <context:component-scan base-package="com.newbie"/>
    步骤二:定义类组件时,添加@Component注解
    //使用注解方式进行依赖注入时,Spring容器自动扫描@Component注解的类,进行对象实例化
    @Component            
    public class Person {
        //如需给属性设置初始值,可使用@Value注解方式,给实体类的属性赋值
        @Value("荆小六”)    
        private String name;
     
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
      
    }
    步骤三:使用Bean实例对象
    //需要使用Bean实例对象时,通过ApplicationContext.getBean(“”)进行获取
    public class Test {
        
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
            Person person =(Person) context.getBean("person");
            System.out.println(person);
        }
    }


    3、依赖注入,使用注解的方式自动装配Bean实例对象
       (1) @Autowired注解:自动装配属性。
        在Spring中,可以使用 @Autowired 注解通过字段、setter方法或构造方法来自动装配Bean。
    实现自动装配的步骤:
    步骤一:注册AutowiredAnnotationBeanPostProcessor
      要启用@Autowired,必须注册“AutowiredAnnotationBeanPostProcessor', 通过在Bean配置文件中,添加 <context:annotation-config />配置实现。
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/aop
          http://www.springframework.org/schema/aop/spring-aop.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd
          http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx.xsd">
     
        <context:annotation-config/>
     
    </beans>
    步骤二:定义组件类时,给自动装配的属性添加 @Autowired 注解。它可以在字段、 setter 方法、构造方法中使用。
    @Component
    public class Team {
        @Autowired
        private Person leader;
     
        @Autowired(required = false)
        private Dept dept;
     
        //Getter、Setter方法
    }
     
        (2)required = false|true,指定是否进行依赖检查
        默认情况下,@Autowired将执行相关检查,以确保属性已经装配正常。当Spring无法找到匹配的Bean装配,它会抛出异常。要解决这个问题,可以通过 @Autowired 的“required”属性设置为false来禁用此检查功能。
    @Autowired(required = false)
     
     

    4、解决自动装配时的歧义性(@Primary和@Qualifier)

        我们使用 @Autowired 注解来自动注入一个 Source 类型的 Bean 资源,但如果我们现在有两个 Srouce 类型的资源,Spring IoC 就会不知所措,不知道究竟该引入哪一个 Bean。我们可以会想到 Spring IoC最底层的容器接口——BeanFactory 的定义,它存在一个按照类型获取 Bean 的方法,显然通过 Source.class 作为参数无法判断使用哪个类实例进行返回,这就是自动装配的歧义性。
      为了消除歧义性,Spring 提供了两个注解:
      @Primary 注解:代表首要的,当 Spring IoC 检测到有多个相同类型的 Bean 资源的时候,会优先注入使用该注解的类。
    • 问题:该注解只是解决了首要的问题,但是并没有选择性的问题
    • @Qualifier 注解:上面所谈及的歧义性,一个重要的原因是 Spring 在寻找依赖注入的时候是按照类型注入引起的。除了按类型查找 Bean,Spring IoC 容器最底层的接口 BeanFactory 还提供了按名字查找的方法,如果按照名字来查找和注入不就能消除歧义性了吗?
    • 使用方法: 指定注入名称为 "source1" 的 Bean 资源
    /* 包名和import */
    class JuiceMaker {
        @Autowired
        @Qualifier("source1")
        public void setSource(Source source) {
            this.source = source;
        }
    }
     
     
    二、使用注解的方式,让Sping容器自动扫描组件
    1、在配置文件中,配置由Spring自动扫描组件
        通过注解的方式,Spring容器能够自动扫描包中的文件,然后由Spring容器注册Bean实例。这样,可以有效减少在XML文件中繁琐的Bean类声明。
        配置方式如下:
        (1)首先,在Bean配置文件中,添加<context:component-scan base-pachage=“”>,这意味着,在 Spring 中启用自动扫描功能。其中,base-package 是指明存储组件的包,Spring将扫描所指定的包,并找出注解为@Component的Bean,将其实例注册到 Spring 容器。
    <context:component-scan base-package=“Spring要扫描的包(中间以逗号分隔)" />
        (2)然后,在定义组件类时,显示地添加@Component注解
    @Component
    class TeamDemo  {
        …….
    }
    2、自动扫描组件的四种注释类型
    在Spring2.5中,有4种类型的组件自动扫描注释类型,如下:
    • @Component – 指示自动扫描组件。
    • @Repository – 表示在持久层DAO组件。
    • @Service – 表示在业务层服务组件。
    • @Controller – 表示在表示层控制器组件。
    查看源代码会发现, @Repository、@Service 和 @Controller 都被注解为 @Component类型。因此,以上三种注解 和 @Component注解的功能完全相同,Spring会自动扫描所有组件的 @Component 、@Repository、 @Service 和 @Controller注解。为便于阅读,应该始终声明@Repository,@ Service 或 @Controller 在指定的层,使你的代码更易于阅读。
    //@Controller 注解的源码
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Controller {
        String value() default "";
    }
    3、自定义自动扫描组件的名称
       (1)默认情况下,采用类的首字母小写的形式,作为Bean的名称
    @Component
    class TeamDemo  {
        …….
    }
    //获取Bean实例的方式
    TeamDemo bean = (TeamDemo) context.getBean("teamDemo");
    (2)显示地指定Bean的名称
    @Component("teamDemoSimple")
    class TeamDemo  {
        …….
    }
    //获取Bean实例的方式
    TeamDemo bean = (TeamDemo) context.getBean("teamDemoSimple");
    4、Spring Bean作用域
    在Spring中,bean作用域用于确定哪种类型的 bean 实例应该从Spring容器中返回给调用者。bean支持的5种范围域:
    • 单例 - 每个Spring IoC 容器返回一个bean实例
    • 原型- 当每次请求时返回一个新的bean实例
    • 请求 - 返回每个HTTP请求的一个Bean实例
    • 会话 - 返回每个HTTP会话的一个bean实例
    • 全局会话- 返回全局HTTP会话的一个bean实例
      在大多数情况下,可能只处理了 Spring 的核心作用域 - 单例和原型,默认作用域是单例。
      如果 bean 配置文件中没有指定 bean 的范围,默认作用域是单例。在单例中,每个Spring IoC容器只有一个实例,无论多少次调用 getBean()方法获取它,它总是返回同一个实例。
      如果要将作用域改为原型模式,可在类定义时,增加@Scope("prototype”)  注解,这样每次调用ApplicationContext.getBean(“customer”)是,Sping容器都会重新new一个新的bean实例,进行返回。
    //注解方式,将作用域改为原型
    @Component 
    @Scope("prototype”) 
    public class Customer{
        …….
    }
     
     
    三、给实体类的属性赋值的方式
    1、使用@Value注解的方式,给实体类的属性赋值
      利用spring注解,可以为实体类的属性赋值,作用就类似于在配置文件里赋值一样。
      赋值时的值类型可以是值内容,也可以进行SpEL表达式,同时也可以引入配置文件的值。
      使用@Value赋值时,值类型如下:
    • 基本数值: @Value("荆小六”) 
    • SpEL表达式; @Value("#{24+4}”) ,  @Value("#{teamDemo.name}”)
    • 使用${...}取出配置文件【properties】中的值(在运行环境变量里面的值)。如需配置文件,则需要在配置类上指定文件的路径位置,使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中;加载完外部的配置文件以后使用${}取出配置文件的值
    @Component
    @PropertySource(value = {"classpath:/params.properties"})
    public class Person {
        //1、基本数值
        @Value("荆小六”)        
        private String name;
     
        //2、使用计算结果赋值,age=28
        @Value("#{24+4}”)       
        private Integer age;
     
        //3、取出配置文件【params.properties】中key/valuez值:"sex=男"
        @Value("${sex}”)       
        private String sex;
     
    }
    SpEL表达式的使用介绍:https://www.yiibai.com/spring/spring-el-hello-world-example.html
     2、使用PropertyPlaceholderConfigurer类,从外部配置文件中读取参数值
      很多时候,大多数Spring开发人员只是把整个部署的详细信息(数据库的详细信息,日志文件的路径)写在XML bean配置文件中,但是,在企业环境中,部署的细节通常只可以由系统管理员或数据库管理员来'触碰',他们可能会拒绝直接访问你的bean的配置文件,它们会要求部署配置一个单独的文件,例如,一个简单的性能(properties)文件,仅具有部署细节。可以使用 PropertyPlaceholderConfigurer 类通过一个特殊的格式在外部部署细节到一个属性(properties )文件,以及访问bean的配置文件 – ${variable}.
     
    步骤一:创建一个属性文件(database.properties),包括数据库的详细信息,把它放到你的项目类路径
    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mydb
    jdbc.username=root
    jdbc.password=123456
    步骤二:在声明bean配置文件中,提供一个PropertyPlaceholderConfigurer映射到 刚才创建的“database.properties”属性文件。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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
     
     
        <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="location">
                <value>database.properties</value>
            </property>
        </bean>
     
     
        <bean id="driverManager" class="com.newbie.propertyPlaceholderConfigurer.DriverManager">
            <property name="driverClassName" value="${jdbc.driverClassName}"/>
            <property name="datebaseURL" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
     
     
    </beans>
    步骤三:实体类DriverManager的定义结构
    public class DriverManager {
        private String driverClassName;
        private String datebaseURL;
        private String username;
        private String password;
        
        //Getter、Setter方法
    }
     
     
    四、Spring在创建对象实例或销毁实例时,设置默认执行的方法
    1、在Bean配置文件中设置:
      在bean 配置文件中定义<bean>节点时,使用 init-method 和 destroy-method 属性指定用于在bean初始化和销毁时,执行某些动作的方法
    <bean id="teamDemo" class="com.newbie.initMethod.TeamDemo"
          init-method="afterPropertiesSet" destroy-method="destroy"/>
    @Component
    class TeamDemo  {
        public void afterPropertiesSet() throws Exception {
            System.out.println(“初始化对象时,执行的方法");
        }
        public void destroy() throws Exception {
            System.out.println(“销毁对象实例时,执行的方法");
        }
    }
    2、使用注解的方式进行设置:
      在类定义时,为类初始化和销毁时要执行的方法,添加 @PostConstruct 和 @PreDestroy 注解。其中,@PostConstruct注解 和 init-method功能相同,标识初始化时要执行的方法;@PreDestroy注解 和 destroy-method 功能相同,标识类销毁时要执行的方法。
      注:@PostConstruct 和 @PreDestroy 注解不属于 Spring,它包含在J2EE库- common-annotations.jar中。
    <!--XML文件中,配置“context:annotation-config”支持-->
    <context:annotation-config/>
    <context:component-scan base-package="com.newbie.initMethod"/>
    @Component
    class TeamDemo  {
        @PostConstruct
        public void afterPropertiesSet() throws Exception {
            System.out.println("初始化对象时,执行的方法");
        }
        @PreDestroy
        public void destroy() throws Exception {
            System.out.println("销毁对象实例时,执行的方法");
        }
    }
    //测试类
    class Test{
        public static void main(String[] args) {
            ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            System.out.println(context.getBean("teamDemo"));
            //ConfigurableApplicationContext.close()将关闭该应用程序的上下文,释放所有资源,并销毁所有缓存的单例bean。
            context.close(); 
        }
    }

    五、使用@Bean 装配外部引用文件中的Bean

    • 问题: 以上都是通过 @Component 注解来装配 Bean ,并且只能注解在类上,当你需要引用第三方包的(jar 文件),而且往往并没有这些包的源码,这时候将无法为这些包的类加入 @Component 注解,让它们变成开发环境中的 Bean 资源。
    • 解决方案:
      1.自己创建一个新的类来扩展包里的类,然后再新类上使用 @Component 注解,但这样很 low
      2.使用 @Bean 注解,注解到方法之上,使其成为 Spring 中返回对象为 Spring 的 Bean 资源。(注意:@Configuration 注解相当于 XML 文件的根元素,必须要,有了它才能解析其中的 @Bean 注解)。
      @Bean 的配置项中包含 4 个配置项:
    • name: 是一个字符串数组,允许配置多个 BeanName
    • autowire: 标志是否是一个引用的 Bean 对象,默认值是 Autowire.NO
    • initMethod: 自定义初始化方法
    • destroyMethod: 自定义销毁方法
      使用 @Bean 注解的好处就是能够动态获取一个 Bean 对象,能够根据环境不同得到不同的 Bean 对象。或者说将 Spring 和其他组件分离(其他组件不依赖 Spring,但是又想 Spring 管理生成的 Bean)
     
    /**
     * 在方法上使用@Bean注解,将外部类的实例注册到Spring容器中
     */
    @Configuration
    class ConfigBeanDemo {
        /**
         * 由Spring容器,实例化一个java.lang.String对象,实例的名称为"pName"
         */
        @Bean(name = "pName")
        public String getString() {
            return "简三十六";
        }
     
        /**
         * 由Spring容器,实例化一个java.io.InputStream对象,实例的名称为"pInput"
         */
        @Bean(name = "pInput")
        public InputStream getInputStream() throws Exception {
            return new FileInputStream("/Users/newbie/Documents/project/aaa");
        }
    }
     
    /**
    *  @ComponentScan注解:代表进行扫描,默认是扫描当前包的路径,扫描所有带有 @Component 注解的 POJO。
    */
    @ComponentScan(basePackages = "com.newbie.domain4")
    class ApplicationContextConfig {
    }
     
    /**
     * 在测试类中编写代码,从 Spring IoC 容器中获取到这个 Bean 
     */
    public class TestStringBean {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationContextConfig.class);
            String name = (String) context.getBean("pName");
            InputStream input = (InputStream)context.getBean("pInput");
            System.out.println(name);
            System.out.println(input);
        }
    }
  • 相关阅读:
    中值滤波器(平滑空间滤波器)基本原理及Python实现
    均值滤波器(平滑空间滤波器)基本原理及Python实现
    使用bibtex为latex论文添加参考文献
    【Linux】日志
    【Linux】常用命令
    【Oracle】查看表大小
    【Oracle】to_date兼容YYYYMMDDHH24MISS与YYYY-MM-DD HH24:MI:SS
    【Mybatis】Lexical error
    【JS】上传插件配置
    【2020-10-06】年年岁岁做计划,岁岁年年完不成!
  • 原文地址:https://www.cnblogs.com/newbie27/p/10723233.html
Copyright © 2020-2023  润新知