zoukankan      html  css  js  c++  java
  • Spring 使用纯注解方式完成IoC

    目录


    创建一个简单的Person类

    使用xml方式配置Spring容器并获取bean的过程

    创建xml配置文件

    进行测试

    使用纯注解方式配置Spring容器并获取bean的过程

    创建spring配置类

    进行测试

    配置注解扫描package

    创建带注解的Person类

    创建Spring配置类

    使用xml配置注解扫描package

    使用注解配置扫描package

    使用注解实现注入

    对普通数据类型的属性进行注入

    对引用类型的属性进行注入——构造方法和setter注入

    集合数据类型的注入

    IoC的相关设置

    懒加载

    作用域

    初始化和销毁回调程序


    创建一个简单的Person类

    package cn.ganlixin.pojo;
    
    public class Person {
    
    	private int id;
    	private String name;
    	private String addr;
    	
    	// 隐藏了有参和无参构造方法、setter、getter、toString
    }
    

      

    使用xml方式配置Spring容器并获取bean的过程

      创建xml配置文件

      如果我们要在Spring容器中创建一个Person类的bean,利用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.xsd">
            
    	<bean id="person" class="cn.ganlixin.pojo.Person"></bean>
    </beans>
    

      

      测试代码

      在测试代码中,使用ClassPathXmlApplicationContext类来获取spring上下文,然后通过getBean即可获取Spring中管理的bean了。

    package cn.ganlixin.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import cn.ganlixin.pojo.Person;
    
    public class TestIOC {
    	public static void main(String[] args) {
    		ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    		
    		Person bean = context.getBean("person", Person.class);
    		System.out.println(bean);
    	}
    }
    

      

    使用纯注解方式配置Spring容器并获取bean的过程

      纯注解方法的话,那就舍弃xml配置文件。  

    创建配置类

      如果我们使用纯注解方式实现IoC,那么需要创建一个配置类来代替上面这个xml配置文件,然后就可以不用创建这个xml配置文件了。

    package cn.ganlixin.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import cn.ganlixin.pojo.Person;
    
    @Configuration
    public class MyConfiguration {
    	
    	@Bean
    	public Person person() {
    		return new Person();
    	}
    
    }
    

      解释一下上面这个MyConfiguration类:

      1、创建的配置类,类名随意,但是需要使用@Configuration注解,标识其为配置类,这个类的功能相当于之前的xml配置文件。

      2、public Person person() 这个方法,使用了@Bean注解,这个方法的功能等同于xml中的<bean>标签,方法名对应<bean>标签中的id,方法返回值类型对应<bean>中的class。在方法体中完成对象的实例化即可。

      如果设置bean的id,即不使用方法名作为bean的id,可以在@Bean中直接设置:@Bean("newId")

    测试代码

      注意,在测试的时候,因为没有使用xml配置文件的方式,所以不是使用ClassPathXmlApplicationContext,而是使用AnnotationConfigApplicationContext类,需要接受一个参数,参数就是我们的配置类。

    package cn.ganlixin.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    import cn.ganlixin.config.MyConfiguration;
    import cn.ganlixin.pojo.Person;
    
    public class TestIOC {
    	public static void main(String[] args) {
    		// 这里使用的是AnnotationConfigApplicationContext
    		ApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
    		
    		// 此时的getBean(),第一个参数是MyConfiguration中的某个方法名,因为配置类中的方法名对应<bean>中的id
    		Person bean = context.getBean("person", Person.class);
    		
    		System.out.println(bean);
    	}
    }
    

      上面就实现了使用注解方式来完成让Spring管理bean。

    配置注解扫描package

      前面我们创建了MyConiguration配置类来代替xml配置文件,然后在类中可以定义很多的function来创建对象,每一个function其实是对应一个xml中的一个<bean>标签的。

      这就意味着,创建每一个bean都需要去Myconfiguration配置类中创建一个function,这样其实并不方便,所以可以使用包扫描的方式,包扫描的方式就是在MyConfiguration类上使用@ComponentScan注解指定要扫描哪些package,如果那些package中的class上面有@Component、@Service、@Repository、@Controller这几个注解中的一个,那么spring就会为其创建bean,bean的id默认是类名首字母小写,但也支持自定义。

      注意,上面列举了4个注解,@Component、@Service、@Repository、@Controller的功能一样,都是标识让Spring管理这些类创建的bean,但是他们的语义是有区别的,所以用法也不相同:

      @Component注解,用来普通的javabean上;最纯粹的<bean />

      @Service注解,用在Service层,一般是service.impl包下的类上面;

      @Repository注解,用在数据访问层,也就是DAO层上

      @Controller注解是用在spring mvc中的控制器上面。

    创建包含注解的Person类

      创建Person类,包名为cn.ganlixin.pojo。

    package cn.ganlixin.pojo;
    
    import org.springframework.stereotype.Component;
    
    @Component  //  使用这个注解,bean的id默认是类名首字母小写
    // @Component("person111") 可以手动设置bean的id
    public class Person {
    
    	private int id;
    	private String name;
    	private String addr;
    	
    	// 隐藏了有参和无参构造方法、setter、getter、toString
    }
    

      

    使用注解配置扫描package

    package cn.ganlixin.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan({"cn.ganlixin.pojo", "cn.ganlixin.demo"}) // 指定扫描哪些package
    public class MyConfiguration {
    	
    }
      
    

      

    进行测试

    package cn.ganlixin.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    import cn.ganlixin.config.MyConfiguration;
    import cn.ganlixin.pojo.Person;
    
    public class TestIOC {
    	public static void main(String[] args) {
    		ApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
    		
    		Person bean = context.getBean("person", Person.class);
    		
    		System.out.println(bean);
    	}
    }
    

      

    使用xml配置注解扫描package

      如果要使用配置文件来指定扫描注解的package,需要使用context这个xmlns,下面这个xml配置文件实现了上面MyConfiguration的功能:

    <?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.xsd">
            
        <!-- 需要使用context这个xmlns,然后使用<context:component-scan>指定需要扫描哪些package -->
    	<context:component-scan base-package="cn.ganlixin.pojo, cn.ganlixin.demo"></context:component-scan>
    </beans>
    

      

    使用注解实现注入

      前面介绍了使用注解来让Spring容器来管理bean对象,创建bean的时候,默认都是调用无参构造方法。如果我们为对象的属性赋值,那么就需要进行注入了。

    对普通数据类型的属性注入

      这里的普通数据类型是指几种基本数据类型、以及String,对他们赋值,可以直接使用@Value注解实现。比如下面对Person类的各个属性进行赋值

    package cn.ganlixin.pojo;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component
    public class Person {
    
    	@Value("999")
    	private int id;
    	
    	@Value("Jenny")
    	private String name;
    	
    	@Value("America")
    	private String addr;
    	
    	// 隐藏了有参和无参构造方法、setter、getter、toString
    }
    

      上面的@Value注解接收一个字符串类型的值,Spring会根据属性的类型,自动将字符串类型的值转换为属性类型的数据。

      另外,@Value不仅支持直接指定属性值,使用@Value("${key}")可以读取外部properties配置文件中的配置项key的值,如果要读取外部properties配置文件的值,需要借助xml配置Spring,指定外部properties配置文件。

      作为测试,在classpath(src)下创建一个config.properties,添加一项内容:

    name=hello world
    

      修改Spring配置文件:

    <?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.xsd">
        
        <!-- 指定外部配置文件的路径 -->
        <context:property-placeholder location="classpath:config.properties" />
            
        <!-- 需要使用context这个xmlns,然后使用<context:component-scan>指定需要扫描哪些package -->
    	<context:component-scan base-package="cn.ganlixin.pojo, cn.ganlixin.demo"></context:component-scan>
    </beans>
    

      为Person类中name属性指定值为外部配置文件的name

    package cn.ganlixin.pojo;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component
    public class Person {
    
    	@Value("999")
    	private int id;
    	
    	@Value("${name}")  // 使用外部配置文件中name的值
    	private String name;
    	
    	@Value("America")
    	private String addr;
    	
    	// 隐藏了有参和无参构造方法、setter、getter、toString
    }
    

      测试:

    package cn.ganlixin.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import cn.ganlixin.pojo.Person;
    
    public class TestIOC {
    	public static void main(String[] args) {
    		ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    		
    		
    		Person bean = context.getBean("person", Person.class);
    		
    		System.out.println(bean);
    		// Person [id=999, name=hello world, addr=America]
    	}
    }
    

      

    对引用数据类型的属性进行注入——构造方法和setter注入

      对引用数据类型的属性进行注入时,有两种方式:构造方法注入和setter注入,如果使用xml配置文件形式,分别是用<constructor-args>和<property>标签。

      而如果是使用注解的话,那么就有两个注解可以实现这个功能:@Autowired和@Resource,他们都能实现依赖注入,但是他们也有区别:

      @Resource是Java内置的注解,不能写在方法上,只能写在属性字段上。

      @Autowired是spring提供的注解,即可以写在属性字段上,也可以写在构造方法上,还可以写在setter上。

    package cn.ganlixin.pojo;
    
    import javax.annotation.Resource;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class Company {
    	
    	@Resource   // @Resource只能写在属性之前
    	private Person person1;
    	
    	@Autowired	// @Autowired可以写在属性前
    	private Person person;
    	
    	public Company() {
    		super();
    	}
    
    	@Autowired	// @Autowired也可以写在构造方法前,会自动根据所需参数类型进行注入
    	public Company(Person person1, Person person) {
    		super();
    		this.person1 = person1;
    		this.person = person;
    	}
    
    	@Autowired	// @Autowired还可以写在setter上
    	public void setPerson(Person person) {
    		this.person = person;
    	}
    	
    	public void setPerson1(Person person1) {
    		this.person1 = person1;
    	}
    
    	@Override
    	public String toString() {
    		return "Company [person1=" + person1 + ", person=" + person + "]";
    	}
    }
    

      上面使用@Autowired和@Resource来进行注入的时候,是自动注入的。会根据byName方式,查看spring容器中是否有一个bean的id,该和属性名称相同的,如果有的话,就将这个bean注入到属性中。如果没有的话,就根据byType进行注入,即根据容器中的bean的type进行匹配,这个时候,如果有多个type相同的bean,就会报错,需要使用@Qualifier("bean_id")明确指定注入哪一个bean。

    集合数据类型的注入

      对于集合类型,不建议使用注解方式注入,建议使用xml配置文件方式。

    IoC的相关设置

      除了对bean的注入,还有其他的bean的设置也很重要,比如懒加载、作用域、初始化和销毁时调用的方法。

    懒加载

      懒加载在xml配置中是设置bean的lazy-init属性值,true为设置为懒加载,false为设置为spring容器创建时创建bean,默认不是懒加载。

      可以使用@Lazy注解来设置懒加载,可以在配置类中创建对象的方法上使用,还可以在class的上面设置。

    package cn.ganlixin.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Lazy;
    
    import cn.ganlixin.pojo.Person;
    
    @Configuration
    public class MyConfiguration {
    	
    	@Bean
    	@Lazy
    	public Person person111() {
    		return new Person(8888, "xyz", "beijing");
    	}
    }
    

      

      还可以在class上设置:

    package cn.ganlixin.pojo;
    
    import org.springframework.context.annotation.Lazy;
    import org.springframework.stereotype.Component;
    
    @Component
    @Lazy
    public class Person {
    	private int id;
    	private String name;
    	private String addr;
    	
    	// 隐藏了有参和无参构造方法、setter、getter、toString
    }
    

      

    作用域

      作用域在xml中是设置scope属性,同样的,在注解中,提供了@Scope与之对应。和@Lazy使用相同,可以在配置类和javabean上使用。

    @Component
    @Scope("singleton")
    public class Person {
    
    }
    

        

    package cn.ganlixin.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Scope;
    
    import cn.ganlixin.pojo.Person;
    
    @Configuration
    @ComponentScan("cn.ganlixin.pojo")
    public class MyConfiguration {
    	
    	@Bean
    	@Scope("prototype")
    	public Person person() {
    		return new Person();
    	}
    }
    

      

    初始化和销毁回调程序

      如果是xml配置,可以使用init-method和destroy-method来设置初始话bean和销毁bean的时候调用。

      如果使用注解,可以实现两个接口,并重写两个方法即可:

    package cn.ganlixin.pojo;
    
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.stereotype.Component;
    
    @Component
    public class Person implements InitializingBean, DisposableBean{
    
    	@Override
    	public void afterPropertiesSet() throws Exception {
    		System.out.println("初始化时被调用");
    	}
    	
    	@Override
    	public void destroy() throws Exception {
    		System.out.println("被销毁时调用");
    	}
    }
    

      

      如果不实现InitializingBean, DisposableBean接口,可以使用下面这种方式:

    package cn.ganlixin.pojo;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Person{
    
    	@PostConstruct
    	public void onInit() {
    		System.out.println("初始化时被调用");
    	}
    	
    	@PreDestroy
    	public void onDestroy() {
    		System.out.println("被销毁时调用");
    	}
    	
    }
    

      

      还可以在配置类中进行设置,首先删除Person中的注解,然后修改配置类:

    package cn.ganlixin.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    import cn.ganlixin.pojo.Person;
    
    @Configuration
    @ComponentScan("cn.ganlixin.pojo")
    public class MyConfiguration {
    	
    	@Bean(initMethod="onInit", destroyMethod="onDestroy")
    	public Person person() {
    		return new Person();
    	}
    }
    

      

  • 相关阅读:
    Vue- 对象语法 v-bind:class与对象语法的使用(重要)
    关于vue中$emit事件问题
    深入理解vue.js2.0指令v-for使用及索引获取
    到底vuex是什么?
    Vue.js学习系列二 —— vuex学习实践笔记(附DEMO)
    前端HTML5几种存储方式的总结
    JSON和JS对象之间的互转
    Vue2.0子父组件通信
    C#字符串和16进制转换
    C#中int32 的有效值范围
  • 原文地址:https://www.cnblogs.com/-beyond/p/10479417.html
Copyright © 2011-2022 走看看