首页IT科技spring是怎么管理bean的(day07-Spring管理Bean-IOC-05)

spring是怎么管理bean的(day07-Spring管理Bean-IOC-05)

时间2025-08-05 01:43:40分类IT科技浏览4361
导读:Spring管理Bean-IOC-05 3.基于注解配置bean...

Spring管理Bean-IOC-05

3.基于注解配置bean

3.3自动装配

基本说明:

基于注解配置bean             ,也可以实现自动装配                   ,使用的注解是:@AutoWired或者@Resource

@AutoWired 的规则说明

(1)在IOC容器中查找待装配的组件的类型      ,如果有唯一的bean装配(按类型)             ,则使用该bean装配

(2)如果待装配的类型对应的bean在IOC容器中有多个                   ,则使用待装配的属性的属性名作为id值进行查找      ,找到就装配       ,找不到就抛异常

@Resource 的规则说明

(1)@Resource 有两个属性比较重要                   ,分别是name和type

Spring将@Resource注解的name属性解析为bean的名字             ,而type属性则解析为bean的类型             。所以如果使用name属性       ,则使用byName的自动注入策略                   ,而使用type属性时则使用byType的自动注入策略

(2)如果@Resource没有指定name或者type             ,则先使用ByName注入策略,如果匹配不上                   ,再使用byType策略                   ,如果都不成功就会报错

不管是@AutoWired 还是 @Resource,都保证属性名是规范的写法就可以注入                   。

除了有特殊要求             ,一般推荐使用@Resource

3.3.1应用实例1-@AutoWired

应用实例需求:

以Action             、Service                   、Dao几个组件来进行演示 这里演示UserAction和UserService的两级自动组装

UserService:

package com.li.component; import org.springframework.stereotype.Service; /** * @author 李 * @version 1.0 * @Service 标识该类是一个Service类/对象 */ @Service public class UserService { public void hi(){ System.out.println("UserService hi()..."); } }

UserAction:

package com.li.component; import org.springframework.stereotype.Controller; /** * @author 李 * @version 1.0 * @Controller 标识该类是一个控制器Controller                   ,通常该类是一个Servlet */ @Controller public class UserAction { private UserService userService; public void sayOk() { System.out.println("UserAction 的 sayOk()"); userService.hi(); } }

beans05.xml指定要扫描的包:

<context:component-scan base-package="com.li.component"/>

测试类:

//通过注解来配置Bean @Test public void setProByAutowired() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans05.xml"); UserAction userAction = ioc.getBean("userAction", UserAction.class); System.out.println("userAction=" + userAction); userAction.sayOk(); }

如下      ,当运行到userAction.sayOk();时抛出空指针异常:

这是因为userAction中的属性userService指向null             ,即没有正确的装配UserService对象      。

添加@Autowired注解:

在IOC容器中查找待装配的组件的类型                   ,如果有唯一的bean装配(按照类型组装)      ,则使用该bean装配

@Controller public class UserAction { //在IOC容器中查找待装配的组件的类型       ,如果有唯一的bean装配(按类型)                   ,则使用该bean装配 @Autowired private UserService userService; public void sayOk() { System.out.println("UserAction 的 sayOk()"); userService.hi(); } }

运行结果如下             ,成功调用了userService.hi()方法       ,说明userService对象已经成功装配:

现在我们在beans05.xml容器中再配置两个UserService对象

spring允许同时使用xml配置文件和注解的方式配置bean

<context:component-scan base-package="com.li.component"/> <!--配置两个UserService对象--> <bean class="com.li.component.UserService" id="userService200"/> <bean class="com.li.component.UserService" id="userService300"/>

此时在ioc容器中就有三个UserService对象:

(1)对于自动扫描进去的UserService对象                   ,它的id为它的类名(首字母小写)             。

(2)在xml文件中配置的两个UserService对象             ,它们的id为上面设置的id(userService200      、userService300)

现在我们重新运行测试方法:

//通过注解来配置Bean @Test public void setProByAutowired() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans05.xml"); UserAction userAction = ioc.getBean("userAction", UserAction.class); System.out.println("userAction=" + userAction); userAction.sayOk(); }

问题一:运行会不会报错?

问题二:@AutoWired注解的属性进行自动装配的时候,装配的是哪一个UserService对象?

@Autowired private UserService userService;

答案一:没有报错

答案二: 在@AutoWired注解中                   ,如果待装配的类型对应的bean在IOC容器中有多个                   ,则使用待装配属性的名称作为id值进行查找,找到就装配             ,找不到就抛异常                   。因此装配的是ioc容器中id与待装配属性的属性名一致的对象      。

3.3.2应用实例2-@Resource

使用UserAction和UserService说明                   ,我们在UserAction类的属性userService400添加@Resource注解      ,并给@Resource注解添加name属性值=“userService             ”

package com.li.component; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import javax.annotation.Resource; /** * @author 李 * @version 1.0 * @Controller 标识该类是一个控制器Controller             ,通常该类是一个Servlet */ @Controller public class UserAction { @Resource(name = "userService") private UserService userService400; public void sayOk() { System.out.println("UserAction 的 sayOk()"); userService400.hi(); } }

同时                   ,我们在配置文件beans05.xml文件中又配置了两个UserService对象:

<context:component-scan base-package="com.li.component"/> <!--配置两个UserService对象--> <bean class="com.li.component.UserService" id="userService200"/> <bean class="com.li.component.UserService" id="userService300"/>

也就是说      ,在beans05.xml文件对应的ioc容器中       ,此时一共有三个UserService对象:

(1)@Resource注解中配置的名为userService的对象

(2)在xml文件中配置的两个UserService对象                   ,它们的id为上面设置的id(userService200             、userService300)

那么在UserAction类的userService400属性中             ,spring给此属性自动装配的是三个中的哪一个对象呢?

答:id名为“userService                   ”的对象       。因为Spring将@Resource注解的name属性解析为bean的名字                   。 至于UserAction类的属性是什么名字无所谓             。

Spring将@Resource注解的type属性则解析为bean的类型       。

现在我们将UserAction类中的注解改为type=UserService.class       ,表示按照UserService.class的类型来进行装配

@Resource(type = UserService.class) private UserService userService400;

这意味着在ioc容器中                   ,只能有一个UserService类型的对象                   。如果配置了多个             ,就会报错:

问题:如果我们在@Resource注解的属性下什么都不写,会如何装配对象?

@Resource private UserService userService400;

分析如下:现在ioc容器中                   ,还是有三个UserService对象:

(1)@Resource注解中配置的对象(当没有指定name时                   ,该对象对应的id就是“userService      ”)

(2)xml文件中配置的两个UserService对象,它们的id为上面设置的id(userService200                   、userService300)

如果@Resource没有指定name或者type             ,则先使用ByName注入策略                   ,如果匹配不上      ,再使用byType策略             ,如果都不成功就会报错             。

这里首先使用ByName策略                   ,即匹配userService400      ,匹配不上后又使用byType策略       ,显然这里有三个对象                   ,不符合类型匹配。也就是说两种策略都匹配失败             ,因此结果是:运行出错                   。

3.3.3注意事项和细节

如待装配的类型对应的bean在IOC容器中有多个       ,则使用待装配的属性的属性名作为id值再进行查找                   ,找到就装配             ,找不到就抛异常 [ByName策略]

可以使用@Autowired和@Qualifier两个注解配合,可以指定装配对象的id值(注意这个id的对象要在ioc容器中存在)

@Autowired @Qualifier(value = "userService200") private UserService userService;

3.4泛型依赖注入

基本说明:

为了更好地管理有继承和相互依赖关系的bean的自动装配                   ,spring还提供基于泛型依赖的注入机制 泛型依赖注入:子类之间的依赖关系由其父类泛型以及父类之间的依赖关系来确定                   ,父类的泛型必须为同一类型                   。通俗一点来说:两个子类之间的依赖关系不需要在子类中去声明,而是在父类中进行了声明             ,而依赖的纽带就是 泛型类型                   ,必须是相同的父类泛型类型才具有依赖关系。 在继承关系复杂的情况下      ,泛型依赖注入就会有很大的优越性

应用实例

现有多个类             ,关系如下:

如上图                   ,如果我们想要在BookService类中使用BookDao属性对象      ,或者要在PhoneService类中使用PhoneDao对象       ,传统方法是将 PhoneDao /BookDao自动装配到 BookService/PhoneSerive 中             。

但是                   ,当这种继承关系多起来时             ,即要自动装配的属性多起来时       ,这种配置方式就显得比较麻烦                   。因此我们可以使用 spring 提供的泛型依赖注入      。

下面模拟图中的类:

Javabean-Phone:

package com.li.depeinjection; /** * @author 李 * @version 1.0 */ public class Phone { }

Javabean-Book:

package com.li.depeinjection; /** * @author 李 * @version 1.0 */ public class Book { }

自定义泛型类BaseDao:

package com.li.depeinjection; /** * @author 李 * @version 1.0 * 自定义泛型类 */ public abstract class BaseDao<T> { public abstract void save(); }

BookDao继承BaseDao                   ,指定泛型Book             ,并添加@Repository注解

package com.li.depeinjection; import org.springframework.stereotype.Repository; /** * @author 李 * @version 1.0 */ @Repository public class BookDao extends BaseDao<Book> { @Override public void save() { System.out.println("BookDao save()"); } }

PhoneDao同样继承BaseDao,指定泛型Phone                   ,并添加@Repository注解

package com.li.depeinjection; import org.springframework.stereotype.Repository; /** * @author 李 * @version 1.0 */ @Repository public class PhoneDao extends BaseDao<Phone>{ @Override public void save() { System.out.println("PhoneDao save()"); } }

自定义泛型类BaseService:

package com.li.depeinjection; import org.springframework.beans.factory.annotation.Autowired; /** * @author 李 * @version 1.0 * 自定义泛型类 */ public class BaseService<T> { @Autowired private BaseDao<T> baseDao; public void save() { baseDao.save(); } }

BookService继承BaseService                   ,指定泛型Book,并添加@Service注解

package com.li.depeinjection; import org.springframework.stereotype.Service; /** * @author 李 * @version 1.0 */ @Service public class BookService extends BaseService<Book> { //并没有写属性 }

PhoneService也继承BaseService             ,指定泛型Phone                   ,并添加注解@Service

package com.li.depeinjection; import org.springframework.stereotype.Service; /** * @author 李 * @version 1.0 */ @Service public class PhoneService extends BaseService<Phone>{ //并没有写属性 }

在配置文件beans06.xml中配置要扫描的包:

<context:component-scan base-package="com.li.depeinjection"/>

这意味着在com.li.depeinjection包下      ,添加了四种注解的类将会被进行扫描             ,在这里就是PhoneService类      、BookService类       、PhoneDao类                   、BookDao类

@Controller /@Service/ @Repository/ @Component

现在我们来进行测试:

//通过泛型依赖来配置Bean @Test public void setProByDependencyInjection() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml"); System.out.println("ok"); }

在语句System.out.println("ok");旁打上断点                   ,点击debug      ,可以看到在ioc容器中已经有四个对象:

打开ioc-->beanFactory-->singletonObjects-->table属性       ,展开phoneService对象                   ,可以看到该对象已经自动装载了PhoneDao类型的对象!!

这意味着我们通过泛型依赖注入             ,可以自动装配需要的对象       ,不必像之前一样一个个地为属性添加注解             。

现在我们获取phoneService对象                   ,调用该对象的save()方法:

//通过泛型依赖来配置Bean @Test public void setProByDependencyInjection() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml"); PhoneService phoneService = ioc.getBean("phoneService", PhoneService.class); phoneService.save(); System.out.println("ok"); }

因为PhoneService类中没有实现save方法             ,因此在运行的时候会调用父类BaseService的save()方法,而BaseService的save()方法中又调用了baseDao属性的save()方法.

我们在上图可以知道baseDao的实际对象是PhoneDao类型                   ,根据动态绑定                   ,最终调用了PhoneDao类中的save()方法:

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
chm文件无法显示此页(CHM文件无法访问此页) 租用香港服务器诈骗怎么处理(租用不用备案香港高防服务器好吗)