spring6入门开发案例步骤

  1. 引入依赖
  2. 创建类和方法
  3. 编写配置文件
    4.测试

Spring是如何创建对象的呢?原理是什么?

// dom4j解析beans.xml文件,从中获取class属性值,类的全类名
 // 通过反射机制调用无参数构造方法创建对象
 Class clazz = Class.forName("com.atguigu.spring6.bean.HelloWorld");
 //Object obj = clazz.newInstance();
 Object object = clazz.getDeclaredConstructor().newInstance();

把创建好的对象存储到一个什么样的数据结构当中了呢?
bean对象最终存储在spring容器中,在spring源码底层就是一个map集合,存储bean的map在DefaultListableBeanFactory类中:

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

Spring容器加载到Bean类时 , 会把这个类的描述信息, 以包名加类名的方式存到beanDefinitionMap 中,
Map<String,BeanDefinition> , 其中 String是Key , 默认是类名首字母小写 , BeanDefinition , 存的是类的定义(描述信息) , 我们通常叫BeanDefinition接口为 : bean的定义对象。

IOC原理

  1. xml解析、工厂模式、反射
  2. 画图

耦合度高

耦合度有待降低

IOC过程

  1. 第一步xml配置文件
    <bean id="dao" class="com.happywei.UserDao"></bean>
  2. 有service类和dao类,创建工厂对象
class UserFactory{
  public static UserDao getDao(){
    //1. 读取配置文件,获取类的全类名
    String classValue = class属性值;
    Class clazz = Class.forName(classValue);//2. 反射创建对象
    return (UserDao)clazz.newInstance();
  }
}

IOC(接口)

  • IOC思想基于 IOC容器完成,IOC容器底层就是对象工厂
  • Spring 提供 IOC 容器实现两种方式::(两个接口)
    1. BeanFactory:IOC容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用、加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
    2. ApplicationContext:BeanFactor,接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,加载配置文件时候就会把在配置文件对象进行创建

Bean管理

什么是 Bean 管理
Bean 管理指的是两个操作:1.Spring 创建对象;2. spirng 注入属性

Bean 管理操作有两种方式

  1. 基于 xml 配置文件方式实现
  2. 基于注解方式实现

基于xml方式注入属性

(1)DI:依赖注入,就是注入属性

注入属性的几种方式

  1. 通过set方法
  2. 通过有参构造
  3. 通过xml

set方式注入

import com.atguigu.spring5
class Book{
  private String bname;
  private String bauthor;
}

有参构造注入

import com.atguigu.spring5
class Orders{
  private String oname;
  private String address;
}

特殊类型注入

对象类型注入

比如员工和部门的关系,一个部门有多个员工,部门应是员工的一个属性。
员工类有部门、姓名、年龄等属性;部门有名字等属性。

引用外部bean


注意value变成了ref

引用内部bean

数组类型注入

List集合注入

<bean id="clazzTwo" class="com.atguigu.spring6.bean.Clazz">
    <property name="clazzId" value="4444"></property>
    <property name="clazzName" value="Javaee0222"></property>
    <property name="students">
        <list>
            <ref bean="studentOne"></ref>
            <ref bean="studentTwo"></ref>
            <ref bean="studentThree"></ref>
        </list>
    </property>
</bean>

Bean生命周期

基于XML管理Bean-自动装配

在MVC中,Control类包含Service属性,Service类包含Dao属性,想实现注入得创建set方法。然后去xml文件配置

<bean id="userController" class="com.happywei.controller.UserController" 
      autowire="byType">
</bean>

<bean id="userService" class="com.happywei.service.UserServiceImpl" 
      autowire="byType">
</bean>

<bean id="userDao" class="com.happywei.dao.UserDaoImpl" 
      autowire="byType">
</bean>

<!--注意,如果是通过名字注入,id则需要和类里定义的名字一致;
    比如修改“userDao“为“userDaoImpl”,在userService那里的注入就会报错-->

基于注解管理Bean

Spring实现注解的自动装配如下

  1. 引入依赖
  2. 开启组件扫描
<context:component-scan base-package="com.happywei"></context:component-scan>
  1. 使用注解定义Bean
  2. 依赖注入

开启组件扫描后,去对应的包下面的类加上注解@Component,在属性上面加注解@Autowried实现注入。

@Autowired注入

  1. 通过属性注入
    在Controller、Service、Dao层注入属性。创建对应的接口和对象,在属性上面加@Autowired
  2. set方法注入
    set方法上加@Autowired
  3. 构造方法注入
    声明属性,再写一个包含这个属性的有参构造,在构造方法上面加@Autowired
  4. 形参注入
    和第3点一样,但@Autowired写在参数前面而不是方法名上面
  5. 只有一个有参树构造函数,无注解
    只能有一个构造函数才能这样写
  6. @Autowired和@Qualifier联合
    注入的时候是类型注入,写的是接口(UserDao、UserService,而非UserDaoImpl),但如果接口UserDao有两个实现类,那么@Autowired类型注入就会报错。此时只能用名称注入。
    假设UserDao有两个实现类,一个UserDaoImpl、一个UserRedisDaoImpl。可以在声明属性UserDao上面加@Autowired@Qualifier(value = "userRedisDaoImpl")//默认实现类名首字母小写

@Resource注入

  • @Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。
  • @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。
  • @Resource注解用在属性上、setter方法上。
  • @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

1、根据name注入

Controller注入Service,在Service实现类上加@Service(value = "myUserService"),在Controller类里面声明service属性,在属性上面加@Resource(name = "myUserService")

2、不指定名字,根据属性名称注入

例如在Service里注入Dao,@Resource后面不加name,但是默认值是属性的名称。即myUserDao,它回根据myUserDao去找

3、既没有指定名字,也没有找到匹配

按类型注入

全注解开发

写一个配置类,在配置类上加@Configuration@ComponentScan("com.happywei.spring6")
这样就代替了xml.所以在测试类里面不用读取xml文件。而是读取配置类通过

ApplicationContext context = new AnnotationConfigApplicationContext(Spring6Config.class);

手写Ioc

实现过程

创建测试类

我们可以通过在实现类添加注解@Service和@Repository,在属性添加@Autowired实现对象的创建和注入。
但现在我们要自己写Bean对象的创建和注入的注解。

创建注解

创建bean容器接口

在Ioc里面用到对象BeanFactory,是基于工厂模式+反射创建对象;而我们用到的是它的子接口;ApplicationContext,这个子接口有更多的实现类,针对不同场景做不同功能。我们也效仿这些功能。(即BeanFactory和它的子接口)
BeanFactory用的是工厂,工厂返回对象,所以接口应该有返回对象的方法。

public interface ApplicationContext {
    Object getBean(Class clazz);
}
public class AnnotationApplicationContext implements ApplicationContext{
    @Override
    public Object getBean(Class clazz) {
        return null;
    }
}

spring里面Ioc创建对象后会放入map集合,我们也创建一个。
在实际使用中,我们会先创建ApplicationContext对象,传入需要扫描的包路径。所以AnnotationApplicationContext 的有参构造接收的参数是String类型。此时拿到路径后,要做的是把路径下包含@Bean注解的类全部实例化,并且存入map容器中。再实现注入。即完成两件事,实例化和注入;
实例化通过拿到类的全类名用反射创建。再存入map中,key是类,value是object.

属性注入:拿到map集合里的所有对象,通过获得对象的class对象拿到属性数组,遍历这个数组,如果有@Di这个注解就注入。
遍历map用entryset,对象就在Object obj = entry.getValue()里面。获取class对象并得到属性数组Fild[]
field.set(obj,beanFactory.get(field.getType()))
field.set表示向里面设置值,第一个参数obj表示当前对象设置值,设置什么呢,设置这个属性,field.getType()是属性的类型,可以是service可以是dao。也就是把beanFactory中的Bean对象通过反射设置给(注入)对象中的属性。

posted @ 2024-02-25 22:57  不会des  阅读(23)  评论(0编辑  收藏  举报