Spring的自动装配(byName;byType)

§1 什么是自动装配? 
§2 自动装配的意义? 
§3 自动装配有几种类型? 
§4 如何启用自动装配? 
§5 自动装配将引发的问题? 






§1 什么是自动装配? 

Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系。因此,如果可能的话,可以自动让Spring通过检查BeanFactory中的内容,来替我们指定bean的协作者(其他被依赖的bean)。


简而言之,就是对于bean当中引用的其他bean不需要我们自己去配置它改使用哪个类,Spring 的自动装配可以帮助我们完成这些工作。


§2 自动装配的意义? 
引用
理解自动装配的优缺点是很重要的。其中优点包括: 


自动装配能显著减少配置的数量。不过,采用bean模板(见这里)也可以达到同样的目的。 


自动装配可以使配置与java代码同步更新。例如,如果你需要给一个java类增加一个依赖,那么该依赖将被自动实现而不需要修改配置。因此强烈推荐在开发过程中采用自动装配,而在系统趋于稳定的时候改为显式装配的方式。


§3 自动装配有几种类型?  
Spring reference 写道
5种模式 说明 
no       默认不使用autowiring。 必须显示的使用"<ref />"标签明确地指定bean合作者,对于部署给予更大的
控制和明了。 


byName 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自
动装配。例如,在bean定义中将 autowire设置为by name,而该bean包含master属性(同时提供
setMaster(..)方法),Spring就会查找名为master的bean定义,并用它来装配给master属性。


byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的
bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,
则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置 
dependency-check="objects"让Spring抛出异常。


constructor 与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类
型一致的bean,那么将会抛出异常。 


autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。
如果发现默认的构造器,那么将使用byType方式。 




§4 如何启用自动装配? 
你可以参照以下的配置去启用自动装配 
引用
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xmlns:tx="http://www.springframework.org/schema/tx" 
xsi:schemaLocation=" 
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
default-autowire="byType" >


当然,这里的byType你可以更改为其他你想要的装配类型。 


§5 自动装配将引发的问题? 


自动装配的一些缺点: 


尽管自动装配比显式装配更神奇,但是,正如上面所提到的,Spring会尽量避免在装配不明确的时候进行猜测,因为装配不明确可能出现难以预料的结果,而且Spring所管理的对象之间的关联关系也不再能清晰的进行文档化。


对于那些根据Spring配置文件生成文档的工具来说,自动装配将会使这些工具没法生成依赖信息。 


自动装配可以减轻配置的工作量,但同时使得配置文件的可读性变得很差,因为你不可能从配置文件 
中获知这些对象之间得依赖关系,从而维护困难! 
注意: 
当根据类型进行自动装配的时候,容器中可能存在多个bean定义跟自动装配的setter方法和构造器参数类型匹配。这样就会存在模棱两可的问题。如果bean定义不唯一,装配时就会抛出异常。
解决方案(任选其一): 
1 放弃使用自动装配,使用显示装配。 
2 将bean排除在自动装配之外, 
引用


两个功能: 
1 通过设定bean定义中的'autowire-candidate'属性显式的设置为'true' 或 'false'来设置其是否为被自动装配
对象。 
2 使用对bean名字进行模式匹配来对自动装配进行限制,其做法是在<beans/>元素的 
'default-autowire-candidates' 属性中进行设置。可以使用通配符,如以'Repository'结尾的bean,
那么可以设置为"*Repository“。 


3 通过在bean定义中设置'primary'属性为'true'来将该bean设置为首选自动装配bean。 
如何使用Spring autowire请取决于你的项目设计。 



进一步理解自动装配:

Spring的自动装配(byName;byType)    好处:大幅度减少Spring配置

   坏处:依赖不能明确管理,可能会有多个bean同时符合注入规则。没有清晰的依赖关系。 
          1,byName  根据属性名自动装配。此选项将检查容器并根据名字查找
                                  与属性完全一致的bean,并将其与属性自动装配。
           2,byType   如果容器中存在一个与指定属性类型相同的bean,那么将与
                                  该属性自动装配;如果存在多个该类型bean,那么抛出异常,
                                  并指出不能使用byType方式进行自动装配;如果没有找
                                  到相匹配的bean,则什么事都不发生,也可以通过设置
看代码:
UserDAO的实现类 有一个属性daoId
public class UserDAOImpl implements UserDAO {
 private int daoId;
 public int getDaoId() {
  return daoId;
 }
 public void setDaoId(int daoId) {
  this.daoId = daoId;
 }
 public void save(User user) {
  System.out.println("user saved!");
 }
 @Override
 public String toString() {
  return "daoId=" + daoId;
 }
}
UserService 依赖了UserDAO
public class UserService {
 
 private UserDAO userDAO;  
 public void add(User user) {
  userDAO.save(user);
 }
 public UserDAO getUserDAO() {
  return userDAO;
 }
 public void setUserDAO(UserDAO userDAO) {
  this.userDAO = userDAO;
 }
 
}


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 name="userDAO" class="com.bjsxt.dao.impl.UserDAOImpl">
   <property name="daoId" value="1"></property>
  </bean>
  
  <bean name="userDAO2" class="com.bjsxt.dao.impl.UserDAOImpl">
   <property name="daoId" value="2"></property>
  </bean>
 
  <bean id="userService" class="com.bjsxt.service.UserService"  autowire="byName">

<!-- 这里的byName是按照属性名进行匹配 这里我们并没有注入UserDAO 但是你的UserService属性名称是UserDAO 所以就相当于 你注入了UserDAO-->
相当于这样  <property name="userDAO" ref="userDAO"/>
  </bean>
  
</beans>
 
测试:
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
  
  
  UserService service = (UserService)ctx.getBean("userService");
  
  System.out.println(service.getUserDAO());


打印出来是1 说明默认注入的是UserDAO
----------

改成byType的话 是按照类型自动装配 如果按照上面的写法 就把autowire="byType">  那么将会报错 因为你的UserDAO 和UserDAO1的类型是一样的 都是class="com.bjsxt.dao.impl.UserDAOImpl" 的




下面通过完整的例子,来说明自动装配:

public interface UserDAO {
	public void save(User user);
}


public class UserDAOImpl implements UserDAO {
	public void save(User user) {
		System.out.println("user saved!");
	}
}

public class User {
	private String username;
	private String password;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}


public class UserService {
	private UserDAO userDAO;  
	public void init() {
		System.out.println("init");
	}
	public void add(User user) {
		userDAO.save(user);
	}
	public UserDAO getUserDAO() {
		return userDAO;
	}
	<strong>@Autowired</strong>
	public void setUserDAO(UserDAO userDAO) {
		this.userDAO = userDAO;
	}
	public void destroy() {
		System.out.println("destroy");
	}
}

<?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-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<strong><context:annotation-config /></strong>
  <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl">
 <bean id="userService" class="com.bjsxt.service.UserService" >
  </bean>
</beans>

这里用的是@Autowired注解,非常简单。


假如说有两个相同的bean,配置文件如下:

<?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-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<strong>  <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl">
  </bean>
 <bean id="u2" class="com.bjsxt.dao.impl.UserDAOImpl"></bean>
 
  <bean id="userService" class="com.bjsxt.service.UserService" ></strong>
  </bean>
</beans>


Spring中默认的自动装配是按照byType自动装配的,但是两个<bean>指向的是同一个类型:
<strong>class="com.bjsxt.dao.impl.UserDAOImpl"></strong>
怎么解决呢?

这样装配一下就行了:

@Autowired
	public void setUserDAO<strong>(@Qualifier("u")</strong> UserDAO userDAO) {
		this.userDAO = userDAO;
	}
用到了:@Qualifier,指定<bean>的名字就行了。


同样还是上面的问题,还一种解决方法就是用:@Resource     //就是资源的意思

@Resource(name="userDAO")
	public void setUserDAO( UserDAO userDAO) {
		this.userDAO = userDAO;
	}



下面介绍:@Component("u") ,实现配置文件零配置       @Repository @Service  @Controller  @Component这四个注解在很多版本中的作用一模一样的,还没有区分出来

<?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-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
	<strong><context:annotation-config />
	<context:component-scan base-package="com.bjsxt"/>   //配置后,Spring自动扫描package为com.bjsxt下的所有文件</strong>
</beans>

在代码中我们这样配置

<strong>@Component("u")               //相当于@Component(value="u")</strong>
public class UserDAOImpl implements UserDAO {
	public void save(User user) {
		System.out.println("user saved!");
	}

}


<strong>@Component("userService")      //相当于@Component(value="userService")</strong>
public class UserService {
	private UserDAO userDAO;  
	public void init() {
		System.out.println("init");
	}
	public void add(User user) {
		userDAO.save(user);
	}
	public UserDAO getUserDAO() {
		return userDAO;
	}
	<strong>@Resource(name="u")</strong>
	public void setUserDAO( UserDAO userDAO) {
		this.userDAO = userDAO;
	}
	public void destroy() {
		System.out.println("destroy");
	}
}


测试代码:

public class UserServiceTest {
	@Test 
	public void testAdd() throws Exception {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
		UserService service = (UserService)ctx.getBean("userService");
		service.add(new User());
		ctx.destroy();
	}
}

这样利用注解配置即可, 分析流程:在配置文件配置以后,自动扫描对应包下面的文件,找@Component注解,一旦找到了@Component,就实例化该类,创建其对象,@Component("K"),并为该实例取名为K值



再看一个常用的注解:@Component("userService")构造完成之后执行,     @PreDestroy对象销毁之前执行

@Component("userService")
public class UserService {
	
	private UserDAO userDAO;  
	
	@PostConstruct
	public void init() {
		System.out.println("init");
	}
	
	public void add(User user) {
		userDAO.save(user);
	}
	public UserDAO getUserDAO() {
		return userDAO;
	}
	
	@Resource(name="u")
	public void setUserDAO( UserDAO userDAO) {
		this.userDAO = userDAO;
	}
	

	@PreDestroy
	public void destroy() {
		System.out.println("destroy");
	}
}


最后小结:

7.自动装配
a)Spring_0800_IOC_AutoWire
b)byName
c)byType
d)如果所有的bean都用同一种,可以使用beans的属性:default-autowire
8.生命周期
a)Spring_0900_IOC_Life_Cycle
b)lazy-init (不重要)
c)init-method destroy-methd 不要和prototype一起用(了解)
9.Annotation第一步:
a)修改xml文件,参考文档<context:annotation-config />
10.@Autowired
a)默认按类型by type
b)如果想用byName,使用@Qulifier
c)写在private field(第三种注入形式)(不建议,破坏封装)
d)如果写在set上,@qualifier需要写在参数上
11.@Resource(重要)
a)加入:j2ee/common-annotations.jar
b)默认按名称,名称找不到,按类型
c)可以指定特定名称
d)推荐使用
e)不足:如果没有源码,就无法运用annotation,只能使用xml
12.@Component @Service @Controller @Repository
a)初始化的名字默认为类名首字母小写
b)可以指定初始化bean的名字
13.@Scope
14.@PostConstruct = init-method; @PreDestroy = destroy-method;



















  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring自动装配原理是基于依赖注入(Dependency Injection,简称 DI)实现的。它主要通过以下方式实现自动装配: 1. 组件扫描:Spring 容器会扫描指定包下的所有类,查找带有特定注解(如 @Component、@Service、@Repository 等)的类,将其注册为 SpringBean。 2. 依赖注入:当容器创建 Bean 的实例时,会检查 Bean 的依赖关系。如果某个 Bean 依赖于其他 Bean,容器会自动查找并注入相应的依赖。 - 构造器注入:通过构造方法参数进行依赖注入。 - Setter 方法注入:通过 Setter 方法进行依赖注入。 - 字段注入:通过字段进行依赖注入。 3. 自动装配模式:Spring 提供了多种自动装配的模式,可以在配置文件或注解中指定。 - byName 模式:根据属性名进行自动装配。 - byType 模式:根据属性类型进行自动装配。 - constructor 模式:根据构造器参数类型进行自动装配。 4. 解决冲突:当存在多个符合条件的 Bean 时,Spring 可以根据一定的规则解决冲突,如使用 @Primary 注解指定首选 Bean,或使用 @Qualifier 注解限定特定的 Bean。 5. 生命周期管理:Spring 容器负责管理 Bean 的生命周期,包括创建、初始化、销毁等操作。 通过以上机制,Spring 实现了自动装配,减少了手动配置的工作量,提高了开发效率和代码的可维护性。同时,它也能够实现松耦合,使组件之间的依赖关系更加灵活和可变。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值