培训第2个月的第11天----@Autowired注解和@Resource注解

               spring框架的两个重要功能就是IOC控制反转 和属性注入。这里要说一下,控制反转也就是 将创建对象的任务交给spring来完成,这种功能有两种实现方式,一是通过xml配置bean标签的方式,一种是通过扫描包(注解)的方式。

               然而在用两种方式的过程中,难免会有疑惑,可不可以同一个bean配置不同的标识呢?@Autowired注解和@Resource注解有什么区别呢?还有其他的一些疑问,我都做了一个小小的验证。

               下面我们来看一下这些验证。

一.所需要的代码部分

                1.UserDaoImpl代码

package com.java.DaoImpl;

import org.springframework.stereotype.Repository;

import com.java.Dao.UserDao;

@Repository
public class UserDaoImpl2 implements UserDao {

	@Override
	public void save() {
		System.out.println("UserDaoImpl2 中的save()方法被调用");
		
	}

}

                2.UserServiceImpl代码

package com.java.serviceImpl;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;

import com.java.Dao.UserDao;
import com.java.DaoImpl.UserDaoImpl2;
import com.java.service.UserService;

public class UserServiceImpl2 implements UserService{
    //用接口来接收实现类
	//@Autowired
	@Resource
	private UserDao userDao;
	@Autowired
	private UserDaoImpl2 userDaoImpl2;
	
	@Override
	public void text() {
		System.out.println("UserServiceImpl2  中的text() 方法被执行");
		System.out.println(userDao);
		System.out.println(userDaoImpl2);
		
	}

}

                   3.applicationContext代码

<?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-3.2.xsd
			  http://www.springframework.org/schema/context
                 http://www.springframework.org/schema/context/spring-context-4.2.xsd"
			

>

<!-- 验证Autowired注解和Resource注解的差别 -->
             
              <!-- 配置UserDaoImpl,是该类交给spring管理,
                                                     创建该类的bean 并放到IOC容器中。
              -->
              
              <bean id="userServiceImpl2" class="com.java.serviceImpl.UserServiceImpl2">
                 <!--  
                     <property name="userDaoImpl2" ref="userDaoImpl2"></property>
                     <property name="userDao" ref="userDaoImpl2"></property>
                  -->
              </bean>
              
            
              <!--   
              <bean id="userDao" class="com.java.DaoImpl.UserDaoImpl2">
              </bean>
               -->
              <bean id="userDao1" class="com.java.DaoImpl.UserDaoImpl2">
              </bean>
              <!-- 用扫描包 的形式取代xml的形式,来将UserDaoImpl2来注入到容器中  
              
              <context:component-scan base-package="com.java.DaoImpl" use-default-filters="true">
                 
              </context:component-scan>
              
              -->
            


</beans>

                  4.测试代码

package com.java.text;

import javax.annotation.Resource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.java.Dao.UserDao;
import com.java.DaoImpl.UserDaoImpl2;
import com.java.serviceImpl.UserServiceImpl2;

//测试Autowired注解和Resource注解的区别
public class Text2 {
      //读取(加载)spring的核心配置文件,为成员变量进行初始化
	  ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext2.xml");
      public static void main(String[] args) {
    	  Text2 text2= new Text2();
    	  text2.text();
    	
	}
      
      public void text() {
    	  UserServiceImpl2 userServiceImpl2 = applicationContext.getBean(UserServiceImpl2.class);
    	  System.out.println(applicationContext.getBean("userServiceImpl2"));
    	  userServiceImpl2.text();
    	  System.out.println((UserDaoImpl2)applicationContext.getBean("userDao1"));
      }
}


   /*如果在xml文件中,没有定义一个bean,或者定义了一个bean,但是没有为其类中的对象属性
    *赋值,那么这个属性就为空。
    *在用xml配置bean的时候,要给这个属性提供set方法,否则对象属性不会被注入进去,会出现
    *异常。
    *如果用注解方式配置bean,会使拥有注解的类直接变成bean放入IOC容器中。默认的getBea
    *n的参数名为类的首字母小写。并且,即使属性没有set函数,那么也可以将对象注入进去。
    *再用@Autowired注解进行属性注入时,注解所修饰的属性类型一定要在IOC容器中存在,否则
    *会出现类型找不到的异常。
    *如果用@Resource注解时,注解所修饰的属性类型如果在IOC容器中不存在,并且属性名也不再
    *容器中,那么就会出现类型找不到的异常。
    *在ioc容器中的类型bean,一个类型只能由一个索引,也就是ID值,否则会出现No qualify
    *ing bean of type 'com.java.DaoImpl.UserDaoImpl2' available:
    * expected single matching bean but found 2: userDao,UserDao
    * Impl2  这个异常。 
    *注解修饰的属性,如果想要注入属性,那么只能是通过扫包方式将bean放进IOC容器中的,用<bean>
    *标签的方式使bean放进IOC容器中的对象,不能通过注解注入进对象。
    *可以通过分号,或逗号的方式,来扫描多个包。
    *用@Autowired注解时,如果一个注解修饰了一个父类或接口,如果IOC容器中用子类类型,那么就
    *会将子类类型对象给接口或父类类型。但是如果又两个实现类类型,会出现接口不知道用哪个实现类的异常。
    *这里并不需要扫描接口所在的包,只需要扫实现类的包即可。
    *用@Resource注解时,是先找名称,如果ID标识没有找到,再去找类型,但是如果这个时候满足的类型
    *比较多,会发生异常。
    * */

二.总结

              1)如果在xml文件中,没有为一个类定义一个bean,或者定义了一个bean,但是没有为其类中的对象属性赋值(进行关联),那么访问这个类的这个属性时就为空。

              2)在用xml方式配置bean的时候,要给这个属性提供set方法,否则对象属性是不会被注入进去的,会出现要我们提供setter的异常。

               3)如果用扫描包的方式为类配置bean,会使被注解修饰的类直接变成bean放入IOC容器中。默认的getBean()的参数名为类的首字母小写。并且,即使属性没有set函数,那么也可以将对象注入进去。用@Autowired注解进行属性注入时,注解所修饰的属性类型一定要在IOC容器中存在(实现类类型存在也可以),否则会出现类型找不到的异常。

               4)通过bean标签的方式将bean放到IOC容器时,并不能是通过注解的方式将对象注入到属性中,只有通过扫描包的方式配置bean的时候才可以将IOC中的bean注入到注解修饰的属性中。

              5)如果用@Resource注解时,JVM会先通过属性名来去IOC容器中找bean,如果没有找到则在通过属性类型来寻找(包括实现类类型)找到了就将bean注入到属性中。@Resource注解所修饰的属性类型如果在IOC容器中不存在,并且属性名也不再容器中,那么就会出现类型找不到的异常。

              6)在通过bean标签的方式配置到容器中的类型bean,一个类型只能yo一个有,也就是ID值,在getBean()的时候通过ID值来获取。但是通过否则会出现No qualifying bean of type com.java.DaoImpl.UserDaoImpl2' available: expected single matching bean but found 2: userDao,UserDao Impl2  这个异常。

             注意:这个 7)  是一个重点!!!!!

             7)对于所谓的单例和多例对象,只是对于在IOC容器的一个bean而言,但是一旦类型一样,但是id标识不一样,那么就认为这几个bean不同。所以在通过 id标识进行getBean()时,它们是不同的对象,这是可以验证的。这里用@Autowired时,由于@Autowired注解是通过类型来进行查找的,所以一旦IOC容器中有相同的类型bean(无论是通过xml配置的bean,还是通过扫描包配置的bean,还是两者混杂),那么就会发生异常。但是@Resource就不发生异常,这是因为@Resource首先是按属性名进行查找的,所以就算有相同的类型bean,只要属性名有对应的id标识,那么就会将属性注入进去。总的来说,就是@Autowired注解只按类型来查找,而@Resource注解是先按属性名来进行查找,如果查找不到,在用类型进行查找。

             8)在扫描包时,可以通过分号,或逗号的方式,来扫描多个包。

             9)用@Autowired或者@Resource注解时,如果一个注解修饰了接口,如果IOC容器中用实现类类型,那么就会将实现类类型对象给接口类型。但是如果有两个实现类类型,会出现接口不知道用哪个实现类的异常(这里@Autowired会发生异常,而@Resource却不会,原因如第7条)。这里并不需要扫描接口所在的包,只需要扫实现类的包即可(因为在实现类中已经和接口有联系了)。

            10)在用注解方式注入时,我们可以指定类被getBean()时的别名,和类是否是单例或者多例。

   

              Over----------------------------------------------

猜你喜欢

转载自blog.csdn.net/qq_41160264/article/details/82261502