spring-ioc

组件和组件的管理概念

组件就是可以复用的java对象

核心容器理解

Spring IoC / DI 实现步骤

1,配置元数据(配置)

配置元数据,既是编写交给SpringIoC容器管理组件的信息,配置方式有三种。 基于 XML 的配置元数据的基本结构:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 此处要添加一些约束,配置文件的标签并不是随意命名 -->
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="..." [1] class="..." [2]>  
    <!-- collaborators and configuration for this bean go here -->
  </bean>

  <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
  </bean>
  <!-- more bean definitions go here -->
</beans>

Spring IoC 容器管理一个或多个组件。这些 组件是使用你提供给容器的配置元数据(例如,以 XML <bean/> 定义的形式)创建的。

  • id 属性是标识单个 Bean 定义的字符串。
  • class 属性定义 Bean 的类型并使用完全限定的类名。

2,实例化ioc容器

提供给 ApplicationContext 构造函数的位置路径是资源字符串地址,允许容器从各种外部资源(如本地文件系统、Java CLASSPATH 等)加载配置元数据。 我们应该选择一个合适的容器实现类,进行IoC容器的实例化工作:

//实例化ioc容器,读取外部配置文件,最终会在容器内进行ioc和di动作
ApplicationContext context = 
           new ClassPathXmlApplicationContext("services.xml", "daos.xml");

3,获取Bean组件

ApplicationContext 是一个高级工厂的接口,能够维护不同 bean 及其依赖项的注册表。通过使用方法 T getBean(String name, Class requiredType) ,您可以检索 bean 的实例。 允许读取 Bean 定义并访问它们,如以下示例所示:

//创建ioc容器对象,指定配置文件,ioc也开始实例组件对象
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
//获取ioc容器的组件对象
PetStoreService service = context.getBean("petStore", PetStoreService.class);
//使用组件对象
List<String> userList = service.getUsernameList();

基于xml的ioc的配置

pom.xml配置文件中引入依赖:

    <dependencies>
        <!--spring context依赖-->
        <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.6</version>
        </dependency>
        <!--junit5测试-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.3.1</version>
        </dependency>
    </dependencies>

并设置打包方式为pom方式:

    <packaging>pom</packaging>

基于无参数构造函数

1,准备组件类

package com.atguigu.ioc;


public class HappyComponent {

    //默认包含无参数构造函数

    public void doWork() {
        System.out.println("HappyComponent.doWork");
    }
}

2,编写配置文件

<!-- 实验一 [重要]创建bean -->
<bean id="happyComponent" class="com.atguigu.ioc.HappyComponent"/>
  • bean标签:通过配置bean标签告诉IOC容器需要创建对象的组件信息
  • id属性:bean的唯一标识,方便后期获取Bean!
  • class属性:组件类的全限定符!
  • 注意:要求当前组件类必须包含无参数构造函数!

基于静态工厂方法实例化

1,准备组件类:

public class ClientService {
  private static ClientService clientService = new ClientService();
  private ClientService() {}

  public static ClientService createInstance() {
  
    return clientService;
  }
}

xml文件:

<bean id="clientService"
  class="examples.ClientService"
  factory-method="createInstance"/>
  • class属性:指定工厂类的全限定符!
  • factory-method: 指定静态工厂方法,注意,该方法必须是static方法。(注意:必须是静态工厂才能用这个指定)

基于实例工厂方法实例化

1,准备组件类

public class DefaultServiceLocator {

  private static ClientServiceImpl clientService = new ClientServiceImpl();

  public ClientServiceImpl createClientServiceInstance() {
    return clientService;
  }
}

2,配置工厂类的组件信息:

    <bean id="defaultServiceLocator" class="com.bubu.ioc_01.DefaultServiceLocator"></bean>

3,通过指定非静态工厂和方法名来配置生成ioc信息

<bean id="clientService2" factory-bean="defaultServiceLocator" factory-method="createClientServiceInstance"></bean>
  • factory-bean属性:指定当前容器中工厂Bean 的名称。
  • factory-method: 指定实例工厂方法名。注意,实例方法必须是非static的!

基于xml的id配置

1,准备组件类

public class UserDao {
}


public class UserService {
    
    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}

2,编写配置类

    <bean id="userDao" class="com.bubu.ioc_02.UserDao"/>
    <bean id="userService" class="com.bubu.ioc_02.UserService">
        <constructor-arg ref="userDao"/>
    </bean>

constructor-arg:构造参数传值的di配置

        value:直接属性值   String="name"  int age = 18

        ref:引用其他bean    (bean的id值)

springioc容器是一个高级容器,内部会有缓存动作:1,先创建对象【ioc】 2,再进行属性赋值【di】,所以bean对象的书写顺序不分先后。

使用不同的方式进行依赖注入:

public class UserDao {
}


public class UserService {
    
    private UserDao userDao;
    
    private int age;
    
    private String name;

    public UserService(int age , String name ,UserDao userDao) {
        this.userDao = userDao;
        this.age = age;
        this.name = name;
    }
}

    <bean id="userDao" class="com.bubu.ioc_02.UserDao"/>
    <bean id="userService" class="com.bubu.ioc_02.UserService">
        <constructor-arg ref="userDao"/>
    </bean>

    <bean id="userService1" class="com.bubu.ioc_02.UserService">

        <constructor-arg value="18"/>
        <constructor-arg value="二狗子"/>
        <constructor-arg ref="userDao"/>
    </bean>

    <bean id="userService2" class="com.bubu.ioc_02.UserService">

        <constructor-arg name="age" value="18"/>
        <constructor-arg name="name" value="二狗子"/>
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>

    <bean id="userSeervice3" class="com.bubu.ioc_02.UserService">

        <constructor-arg index="0" value="18"/>
        <constructor-arg index="1" value="name"/>
        <constructor-arg index="2" ref="userDao"/>
    </bean>

还有一种基于set方法的依赖注入方式:

组件类:

public Class MovieFinder{

}

public class SimpleMovieLister {

  private MovieFinder movieFinder;
  
  private String movieName;

  public void setMovieFinder(MovieFinder movieFinder) {
    this.movieFinder = movieFinder;
  }
  
  public void setMovieName(String movieName){
    this.movieName = movieName;
  }

  // business logic that actually uses the injected MovieFinder is omitted...
}
    <bean id="SimpleMovieLister" class="com.bubu.ioc_02.SimpleMovieLister">
        <property name="" value="" ref=""/>
        <property name="movieFinder" ref="MovieFinder"/>
        <property name="movieName" value="name"/>
    </bean>

注意:

name:属性名=>setter方法的去set和首字母小写的值!用于调用set方法的名

ioc容器的bean获取三种方式

    public void getBeanFromIoc() {
/*1,创建ioc容器对象*/
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-03.xml");
/*2,读取ioc容器的组件*/        
        /*方案一:直接根据beanId获取即可  放回类型是Object 需要强转*/
        HappyComponent happyComponent = (HappyComponent)context.getBean("happyComponent");
        
        /*方案二:根据beanId,同时指定bean的类型 Class*/
        HappyComponent happyComponent1 = (HappyComponent)context.getBean("happyComponent", HappyComponent.class);
        
        /*方案三:直接根据类型获取   注意:使用这种方法时,同一个类型,在ioc容器中只能有一个bean!如果ioc容器中存在多个bean,会出现不唯一异常(前两个方案无需考虑这一点)*/
        HappyComponent happyComponent2 = context.getBean(HappyComponent.class);
    }

注:ioc的配置一定是实现类,但是可以根据接口类型获取值!

public interface A {
    public void doWork();
}


public class HappyComponent implements A{

    //默认包含无参数构造函数
    public void doWork() {
        System.out.println("HappyComponent.doWork");
    }
}
        /*方案三:直接根据类型获取*/
        A happyComponent2 = context.getBean(A.class);
        happyComponent2.doWork();

三层架构组件管理和jdbctemplate使用

依赖引入:

      <!-- 数据库驱动和连接池-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>

        <!-- spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>6.0.6</version>
        </dependency>

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">


    <!--读取外部配置文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>


</beans>

测试代码:

    @Test
    public void testForIoc() {
        /*1,创建ioc容器*/
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-01.xml");
        /*2,获取jdbcTemplate组件*/
        JdbcTemplate jdbcTemplate = (JdbcTemplate) applicationContext.getBean(JdbcTemplate.class);
        /*3,进行数据库的crud动作*/
        String sql = null;
        //插入:
        sql = "insert into students (id,name,gender,age,class) values(?,?,?,?,?)";
        /*参数1:String sql 可以带占位符?   ?只能代替值  不能代替关键字*/
        /*参数2:Object...param传入占位符的值 顺序:从左开始对象*/
        /*放回值:int 影响函数*/
        int rows = jdbcTemplate.update(sql, 9,"二狗子", "男", 18, "三年二班");
        System.out.println("rows=" + rows);

        //查询
        sql = "select * from students where id = ?";
        /*参数1:sql语句 可以使用?*/
        /*参数2:RowMapper 列名和属性名的映射器*/
        Student student1 = jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
            //rs 结果集
            //rowNum 行数
            //rs 结果集中获取的值 赋值给实体类对象即可
            Student student = new Student();
            student.setId(rs.getInt("id"));
            student.setName(rs.getString("name"));
            student.setAge(rs.getInt("age"));
            student.setGender(rs.getString("gender"));
            return student;
        }, 1);
        System.out.println("student1=" + student1);

        //查询所有学生的数据
        sql = "select id,name,gender,age,class as classes from students";
        /*BeanPropertyRowMapper:帮助我们自动映射列和属性值!要求列名和属性名一致!!不一致要起别名*/
        List<Student> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Student>(Student.class));
        System.out.println("query=" + query);

    }

基于注解方式配置ioc

基本扫描配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 配置自动扫描的包 -->
    <!-- 1.包要精准,提高性能!
         2.会扫描指定的包和子包内容
         3.多个包可以使用,分割 例如: com.atguigu.controller,com.atguigu.service等
    -->
    <context:component-scan base-package="com.atguigu.components"/>
  
</beans>

排除包:

<context:component-scan base-package="com.atguigu.components">
    
    <!-- context:exclude-filter标签:指定排除规则 -->
    <!-- type属性:指定根据什么来进行排除,annotation取值表示根据注解来排除 -->
    <!-- expression属性:指定排除规则的表达式,对于注解来说指定全类名即可 -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

指定扫描包:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframewor

Bean组件作用域和周期方法注解

public class BeanOne {

  //周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
  @PostConstruct  //注解制指定初始化方法
  public void init() {
    // 初始化逻辑
  }
}

public class BeanTwo {
  
  @PreDestroy //注解指定销毁方法
  public void cleanup() {
    // 释放资源逻辑
  }
}
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) //单例,默认值
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //多例  二选一
public class BeanOne {

  //周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
  @PostConstruct  //注解制指定初始化方法
  public void init() {
    // 初始化逻辑
  }
}

DI注解:jsr-250注解  Java提供的注解   为spring 提供了一个 @Resource

引入依赖:

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>
@Controller
public class JavaTestController {

    @Resource(name="javaTestIpml")
    public JavaTest javaTest;

    public List<Integer> getJavaTests() {
        List<Integer> list = new ArrayList<>();
        list=javaTest.setList();
        list.forEach(System.out::println);
        return list;
    }
}

相当于:

基本类型注解:@Value        标签的作用

@Component()
public class JavaBean {
    @Value("${jdbc.username:no}")
    private String username;

    @Value("${jdbc.password:no}")
    private String password;

    public void print() {
        System.out.println(username+" and "+password);
    }
}

    @Test
    public void testSpringIoc() {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-02.xml");
        com.bubu.ioc_02.JavaBean bean = context.getBean(com.bubu.ioc_02.JavaBean.class);
        bean.print();
        System.out.println(bean);
    }

如果没有传进来值,默认值为“:”后面的值

ioc三层架构标签的使用

非三层架构建议使用Component

配置文件:

完全注解的使用

//标注当前类是配置类,替代application.xml    
@Configuration
//引入jdbc.properties文件
@PropertySource({"classpath:application.properties","classpath:jdbc.properties"})
@ComponentScan(basePackages = {"com.atguigu.components"})
public class MyConfiguration {

    //如果第三方类进行IoC管理,无法直接使用@Component相关注解
    //解决方案: xml方式可以使用<bean标签
    //解决方案: 配置类方式,可以使用方法返回值+@Bean注解
    @Bean
    public DataSource createDataSource(@Value("${jdbc.user}") String username,
                                       @Value("${jdbc.password}")String password,
                                       @Value("${jdbc.url}")String url,
                                       @Value("${jdbc.driver}")String driverClassName){
        //使用Java代码实例化
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driverClassName);
        //返回结果即可
        return dataSource;
    }
}
// AnnotationConfigApplicationContext-IOC容器对象
ApplicationContext iocContainerAnnotation = 
new AnnotationConfigApplicationContext();
//外部设置配置类
iocContainerAnnotation.register(MyConfiguration.class);
//刷新后方可生效!!
iocContainerAnnotation.refresh();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值