Spring二刷笔记-IOC概念理解以及具体实现(xml和Annotation)
Posted 滑稽404#
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring二刷笔记-IOC概念理解以及具体实现(xml和Annotation)相关的知识,希望对你有一定的参考价值。
文章目录
- IOC:控制反转,Spring两大核心:aop和ioc,直接看字面意思难以理解,直接多练练,通过IDE工具看看源码实现就会懂了,我讲的可能也不是太好,见谅
一、什么是控制反转?
开发者直接创建对象,变成被动接收由IOC容器生成的对象,所有对象交给IOC容器管理,减少了各功能模块之间的耦合度
二、IOC的简单实现
<!--将类交给ioc管理,通过bean对象由ioc生成bean实例 -->
<bean id="user" class="com.chime.service.User"></bean>
//读取指定xml上下文 可以读入多个("bean1.xml","bean2.xml")
ApplicationContext context=new ClassPathXmlApplicationContext("applications.xml");
//获取bean实例
User user = context.getBean("user", User.class);
User user =(User) context.getBean("user");
//指定类型和强转都可以
三、实现原理
UserDao{
//CRUD
}
UserService{
//普通方式 在service生成dao层对象,调用dao层来实现各业务
//这种方式 dao和service联系太紧密 如果dao层出现问题 service就无了
new UserDao();
//CRUD
}
工厂模式:在各类之间建立一个工厂,所有实例化操作全部交给工厂来做,降低耦合
UserFactory{
public UserDao getUserDao{
//springioc就是基于工厂模式+反射实现
//通过反射生成class对象的优势:无论类的路径如何改变,
//只需要知道类的全限定名(UserDao,就是类名)就能生成class,进一步降低了耦合度
//通过反射加载class对象
Class clazz=Class.forName(UserDao.class.getName());
return (UserDao)clazz.newInstance();//class实例化
}
}
四、bean创建对象
<bean id="user" class="com.chime.service.User"></bean>
通过访问User对象的无参构造器构造User对象,如果重载有参构造器后,没有加上无参构造器会报错
五、DI(依赖注入),Bean管理
能够使对象在ioc中生成时,注入属性
1.xml实现Bean管理
(1)默认
<bean id="user" class="com.chime.service.User"></bean>
默认使用无参构造器创建对象
(2)set方法注入
public class Book {
private String name;
private String author;
public void setName(String name) {
this.name = name;
}
public void setAuthor(String author) {
this.author = author;
}
}
//bean通过property访问set方法,来set相对应的属性
<bean id="book" class="com.chime.pojo.Book">
<property name="name" value="斗破苍穹"/>
<property name="author" value="天蚕土豆"/>
</bean>
(3)有参构造注入
public class Book {
private String name;
private String author;
public Book(String name,String author){
this.name=name;
this.author=author;
}
<bean id="book" class="com.chime.pojo.Book">
<constructor-arg name="name" value="武动乾坤"/>
<constructor-arg name="author" value="天蚕土豆"/>
</bean>
(4)注入属性的特殊情况
- 注入空值
<!--中间加空标签-->
<constructor-arg name="author"> <null/> </constructor-arg>
- .特殊符号
因为xml和html是文本语言,所以需要进行转义或者写入CDATA中
(5)注入外部bean
在有些情况,类中需要引用另一个类,如service层中,需要调用dao层,就需要外部bean注入该属性
dao层负责数据,service负责具体业务,很多业务就需要调用dao
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
public int add(){
userDao.add();
return 1;
}
public int delete(){
userDao.delete();
return 1;
}
}
<bean id="userDao" class="com.chime.dao.UserMapper"></bean>
<bean id="userService" class="com.chime.service.UserService">
<property name="userDao" ref="userDao"/>
<!--ref:引用userDao,通过set方法注入-->
</bean>
(6)注入内部bean
<bean id="userService" class="com.chime.service.UserService">
<property name="userDao">
<bean id="userDao" class="com.chime.dao.UserMapper"></bean>
</property>
</bean>
(7)注入集合属性
<bean id="coll" class="com.chime.pojo.Coll">
<property name="arr">
<!--注入数组-->
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
<property name="list">
<!--注入list-->
<list>
<ref bean="beanid"></ref>
<value>Spring</value>
<value>SpringMVC</value>
<value>MyBatis</value>
</list>
</property>
<property name="set">
<!--注入set-->
<set>
<value>算法</value>
<value>前端</value>
<value>后端</value>
</set>
</property>
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PYTHON" value="python"></entry>
<entry key="mysql" value="sql"></entry>
</map>
</property>
</bean>
集合可以通过util命名空间方式 将其提取为公共部分
可以通过ref注入对象集合
<ref bean="beanid"></ref>
(8)注入外部文件
(9)普通bean和工厂bean
- 普通bean:bean定义的什么类型,返回的是什么类型
- 工厂bean:bean定义类型与返回类型不一样,通过实现FactoryBean接口来返回对象
//实现FactoryBean接口,并添加泛型
public class MyBean implements FactoryBean <Book>{
@Override
public Book getObject() throws Exception {
Book book=new Book();
book.setName("茄子白给日记");
book.setAuthor("pdd");
return book;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<bean id="myBean" class="com.chime.pojo.MyBean"></bean>
Book book = context.getBean("myBean", Book.class);
(10)bean的作用域
Book book1 = context.getBean("book", Book.class);
Book book2 = context.getBean("book", Book.class);
System.out.println(book1);
System.out.println(book2);
com.chime.pojo.Book@6737fd8f
com.chime.pojo.Book@6737fd8f
你会发现,getBean两次,输出的是同一地址,表明获取到的是同一实例
<bean id="book" class="com.chime.pojo.Book" scope="singleton"></bean>
<bean id="book" class="com.chime.pojo.Book" scope="prototype"></bean>
- singleton:bean默认作用域是singleton,为单实例,在加载配置文件是就创建了对象,所有getBean获取到的都是同一个实例
- prototype:多实例,设置该作用域之后,就不会在加载配置文件时创建对象了,只会在每次getBean时创建一个新的对象,所以每次get到的不一样
- request和session创建对象的时机也不同,可以了解一下
(11)bean的生命周期
- bean的创建
- 属性的注入
- 初始化
- 获取实例对象(执行)
- 销毁
(12)xml实现自动装配
<bean id="myBean" class="com.chime.pojo.MyBean" autowire="byName"></bean>
<bean id="myBean" class="com.chime.pojo.MyBean" autowire="byType"></bean>
- byName:根据set方法的小写名称,找到xml中与之匹配的bean id
- byType :根据属性类型,找到xml中与之匹配的bean class(因为bean class 唯一,所以byType自动装配,不能有两个同类型的bean)
public class Emp {
private Dept dept2;
public void setDept1(Dept dept1) {
this.dept2 = dept1;
}
}
<bean id="dept1" class="com.chime.pojo.Dept">
<property name="name" value="1"/>
</bean>
<bean id="dept2" class="com.chime.pojo.Dept">
<property name="name" value="2"/>
</bean>
<bean id="emp" class="com.chime.pojo.Emp" autowire="byName"></bean>
就算属性名设置的dept2,但是byName还是根据set方法名称进行匹配
2.注解实现Bean管理
(注解详细使用链接)
spring使用注解前提是引入AOP依赖
(1)组件注释
- @Component
- @Repository
- @Service
- @Controller
@Repository、@Service、 @Controller就是一个Component,(IDEA按住CRTL点击注解就能阅读源码),取不同的名字只是为了区分不同层
//@Component(value="userService") //<bean id="userService" class=currentClass></bean>
@Service(value="userService") //<bean id="userService" class=currentClass></bean>
public class UserService {
}
@Service(value="userService") 相当于实现了<bean id="userService" class=currentClass></bean>
currentClass :当前类
(2)自动装配
- @Autowired:自动装配,根据byType实现,在属性上写上该注解就可以注入属性(前提是已有该bean)
- @Qualifier:需要结合@Autowired一起使用,基于byName实现,在括号中可以写入name,根据name匹配
- @Resource:可以单独使用,既可以byType又可以byName
- @Value(val):给普通属性注入值
以上是关于Spring二刷笔记-IOC概念理解以及具体实现(xml和Annotation)的主要内容,如果未能解决你的问题,请参考以下文章