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

  1. 普通bean:bean定义的什么类型,返回的是什么类型
  2. 工厂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>
  1. singleton:bean默认作用域是singleton,为单实例,在加载配置文件是就创建了对象,所有getBean获取到的都是同一个实例
  2. prototype:多实例,设置该作用域之后,就不会在加载配置文件时创建对象了,只会在每次getBean时创建一个新的对象,所以每次get到的不一样
  3. request和session创建对象的时机也不同,可以了解一下

(11)bean的生命周期

  1. bean的创建
  2. 属性的注入
  3. 初始化
  4. 获取实例对象(执行)
  5. 销毁

(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)自动装配

  1. @Autowired:自动装配,根据byType实现,在属性上写上该注解就可以注入属性(前提是已有该bean)
  2. @Qualifier:需要结合@Autowired一起使用,基于byName实现,在括号中可以写入name,根据name匹配
  3. @Resource:可以单独使用,既可以byType又可以byName
  4. @Value(val):给普通属性注入值

以上是关于Spring二刷笔记-IOC概念理解以及具体实现(xml和Annotation)的主要内容,如果未能解决你的问题,请参考以下文章

Spring二刷笔记-事务(Transaction)概念理解与实现

说说AOP和IOC的概念以及在spring中是如何应用的

Spring学习笔记--环境搭建和初步理解IOC

如何理解Spring IOC

Spring IOC的理解

谈谈对Spring IOC的理解