持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情
FactroyBean
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。
<T> getObject():通过一个对象交给ioc容器来管理
Class<?> getObjectType():设置所提供对象的类型
boolean isSingleton():所提供的对象是否为单例
Factory
import com.sentiment.pojo.User;
import org.springframework.beans.factory.FactoryBean;
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
配置文件
这里并不是返回UserFactoryBean的类对象,而是该类中getObject方法中返回的User()对象,较以往的工厂来说bean工厂省去了找工厂的过程直接找我们需要的对象。
<bean class="com.sentiment.factory.UserFactoryBean"></bean>
测试
@Test
public void factoryTest(){
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("spring-factory.xml");
User bean = ioc.getBean(User.class);
System.out.println(bean);
}
输出结果
可以看到这里实例化了User对象,并输出了对应内容
基于xml的自动装配
根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值
三层架构
自动装配用到了三层架构,先了解了一下
controller
controller又叫web层、控制层、控制器,主要用于用户交互,接收和响应来自用户端的http请求,并且包含一些web功能
常见技术:cookie seesion jsp servlet listener filter
service
service层又叫业务层,主要用来处理逻辑,用于事务处理、日志管理、监控等
dao
dao层又叫持久层、mapper层、respotiry层,主要用于操纵数据库返回用户数组,前篇提到的mybatis就属于该层
技术:jdbc druid mybatis
三层架构的调用关系
controller -> service -> dao -> 操作数据库
数据返回关系
dao操作数据库数据 ->service -> controller
场景模拟
回到xml自动装配,感觉跟动态代理好像。。。
先写一个controller
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void saveUser() {
userService.saveUser();
}
}
controller中定义了UserService并调用了他的saveUser()方法,所以在创建个UserService接口和实现类
UserService接口
public interface UserService {
void saveUser();
}
实现类
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void saveUser() {
userDao.saveUser();
}
}
接着又调用了UserDao的saveUser所以继续创建接口和实现类
UserDao接口
public interface UserDao {
void saveUser();
}
实现类
public class UserDaoImpl implements UserDao {
@Override
public void saveUser() {
System.out.println("保存成功");
}
}
最后通过配置文件自动装配,通过其中的set方法进行赋值
<bean id="userController" class="com.sentiment.controller.UserController">
<property name="userService" ref="userService"></property>
</bean>
<bean id="userService" class="com.sentiment.service.iml.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.sentiment.dao.iml.UserDaoImpl"></bean>
测试
public void test(){
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("spring-autowire.xml");
UserController bean = ioc.getBean(UserController.class);
bean.saveUser();
}
byType
在场景模拟中,用到的并不是自动装配,而是通过property标签手动设置了对应的属性值,所以这里就通过autowire标签的byType属性实现自动装配,若设置no或default属性则表示不会自动装配即使用默认值
<bean id="userController" class="com.sentiment.controller.UserController" autowire="byType">
<!-- <property name="userService" ref="userService"></property>-->
</bean>
<bean id="userService" class="com.sentiment.service.iml.UserServiceImpl" autowire="byType">
<!-- <property name="userDao" ref="userDao"></property>-->
</bean>
<bean id="userDao" class="com.sentiment.dao.iml.UserDaoImpl"></bean>
此时在运行程序后,会通过byType自动匹配对应的类型属性赋值
但需要注意两个问题:
- 若删除userService的bean,则会爆空指针错误,即:当匹配不到对应的bean后,则会不自动装配使用默认值
- 由于是根据类型进行匹配所以当设置多个userService类型的bean,则会报错:NoUniqueBeanDefinitionException,也就是这样会匹配到了多个bean,无法执行
byName
根据bean的id名来进行bean的匹配。
上边提到当设置多个userService类型的bean后,则会报错,这时就可以使用byName因为他是根据bean的id进行匹配的,所以不管设置几个同类型bean,只要id唯一就能匹配到(而id是唯一标识,所以常规状态下不会出现id相同情况)