Spring控制反转-项目创建-Spring容器-依赖注入

Spring简介

Spring是一个开源的控制反转(Inversion of Control ,IoC)和面向切面(Aspect Oriented Programmin ,AOP)的容器框架.

IOC和AOP是它的两个重要特性。

依赖注入(Dependency Injection,DI)是控制反转的重要部分,它的主要目的是简化企业开发。

Spring简化了企业应用程序开发复杂性,弱化了系统组件间的藕合度,它由Rod Johnson创建的。

什么是控制反转(IOC)

所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。

什么是依赖注入(Di)

所谓依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中。

举例说明 Ioc 和 Di

Dao层

public interface StudentDao {
    public int delete();
}

两个实现类:
StudentDaoImplMySql

public class StudentDaoImplMySql implements StudentDao {
    @Override
    public int delete() {
        System.out.println("使用mysql删除数据");
        return 0;
    }
}

StudentDaoImplOracle

public class StudentDaoImplOracle implements StudentDao {
    @Override
    public int delete() {
        System.out.println("使用oracle删除数据");
        return 0;
    }
}

服务层

public class StudentService {
    StudentDao studentDao;

    public StudentService(StudentDao studentDao) {
        this.studentDao = studentDao;
    }

    public void delete() {
        studentDao.delete();
    }
}

使用

public class Test {
    public static void main(String[] args) {
	    //由客户端决定使用那个数据库
        StudentService studentService = new StudentService(new StudentDaoImplMySql());
        studentService.delete();
    }
}

由外部创建要使用的对象,这叫控制反转(本来应该由服务层创建)例如在Spring容器创建对象
客户端将创建的对象传入服务层,这是依赖注入

使用Spring优势

在项目中引入spring立即可以带来下面的好处
降低组件之间的耦合度,实现软件各层之间的解耦。
在这里插入图片描述

可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人员就不再需要手工控制事务,也不需处理复杂的事务传播。
容器提供单例模式支持,开发人员不再需要自己编写实现代码。
容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。
容器提供的众多辅作类,使用这些类能够加快应用的开发,如: JdbcTemplate、 HibernateTemplate。
Spring对于主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts2等,这样更便于应用的开发。

使用Spring需要的jar

使用maven仓库。

使用Idea添加Spring应用

确定项目与maven仓库关联。
在这里插入图片描述
创建maven项目
在这里插入图片描述

    <groupId>com.entor</groupId>
    <artifactId>spring_maven</artifactId>
    <version>1.0-SNAPSHOT</version>

在pom.xml文件中的dependencies标签中添加依赖具体到mvnrepository网址查找

    <dependencies>
   		 <!--所有依赖写在这儿-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.5</version>
        </dependency>
		
    </dependencies>

下载的依赖在:D:\maven\repository\org.springframework\spring-webmvc\5.3.5 中
maven会自动将该依赖的需要的其他jar包一起导入。

当下载失败时,应该将刚刚下载的jar包和依赖删除并且重新刷新maven让其重新下载。
在这里插入图片描述

依赖注入(DI)

使用构造器注入
使用属性setter方法注入
使用Field注入(用于注解方式)
注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。
1.手工装配依赖对象
2.自动装配依赖对象

Spring配置文件(手工装配)

在resource目录下创建applicationContext.xml
在这里插入图片描述

配置文件的属性和赋值(set方法注入和构造方法注入)

    applicationContext.xml文件就是spring容器,把需要该容器创建的对象的类通过bean标签配置在此即可
    默认加载该文件时创建对象,每一个bean标签只创建一个对象,单例模式。
    id="student",获取对象名称,唯一。
    class="com.eator.entity.Student",类的全限定名,根据反射创建对象。
    lazy-init="true"延迟创建对象,在使用该对象时才创建并初始化,缩短spring容器的启动时间,节省内存空间。
    scope="prototype",每次调用创建创建一个新的对象。默认为singleton只创建一个。
    init-method="init对象创建时调用该方法,只执行一次
    destroy-method="destroy对象销毁时调用该方法,只执行一次

set注入和构造方法注入必须在实体类写上对应的set方法和构造方法

set 方法赋值

applicationContext_bean.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--一个bean标签创建一个对象 id值唯一-->
    <!--基本类型赋值-->
    <bean id="student"
          class="com.eator.entity.Student"
          lazy-init="true"
          scope="prototype"
          init-method="init"
          destroy-method="destroy">
        <!--
        赋值,自动调用set方法
        开闭标签内不写东西可以写成单标签
        -->
        <property name="id" value="1"/>
        <property name="name" value="张三"></property>
        <property name="age" value="18"></property>
    </bean>
    <bean id="bean" class="com.eator.entity.Bean">
        <property name="intVal" value="1"/>
        <property name="strVal" value="张三"/>
         <!--数组类型赋值-->
        <property name="arrays">
            <array>
                <value>张三</value>
                <value>李四</value>
                <value>王五</value>
            </array>
        </property>
         <!--list集合赋值-->
        <property name="list">
            <list>
                <value>张三</value>
                <value>李四</value>
                <value>王五</value>
            </list>
        </property>
         <!--set集合赋值-->
        <property name="set">
            <set>
                <value>张三</value>
                <value>李四</value>
                <value>王五</value>
            </set>
        </property>
         <!--Map类型对赋值-->
        <property name="map">
            <map>
                <entry key="CN" value="中国"/>
                <entry key="EN" value="美国"/>
                <entry key="JP" value="日本"/>
            </map>
        </property>
         <!--Properties类型对赋值-->
        <property name="properties">
            <props>
                <prop key="CN">中国</prop>
                <prop key="EN">美国</prop>
                <prop key="JP">日本</prop>
            </props>
        </property>
    </bean>
</beans>

构造方法和引用(ref、实体类赋值)赋值

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

   <!--导入其他配置文件,按照导入顺序加载,bean的创建顺序默认根据配置的先后顺序创建对象-->
   <import resource="applicationContext.xml"></import>
   <bean id="bean1" class="com.eator.entity.Bean1">
      <!--
      set 方法
      <property name="bean2" ref="bean2"/>
      <property name="bean3" ref="bean3"/>
      -->

      <!--构造方法 index第几个参数 ref 引用bean的id -->
      <constructor-arg index="0" ref="bean2"/>
      <constructor-arg index="1" ref="bean3"/>
   </bean>
   <bean id="bean2" class="com.eator.entity.Bean2"></bean>
   <bean id="bean3" class="com.eator.entity.Bean3" ></bean>
</beans>

属性注解注解Autowired、Qualifier和Resource的使用

开启注解:修改头部参数,和添加标签<context:annotation-config/>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启注解模式 只有开启注解模式注解才能获取配置文件内的对象-->
    <context:annotation-config/>
    <!--导入其他配置文件,按照导入顺序加载,bean的创建顺序默认根据配置的先后顺序创建对象-->
    <import resource="applicationContext.xml"></import>
    <bean id="bean1" class="com.eator.entity.Bean1">
    </bean>
    <bean id="bean2" class="com.eator.entity.Bean2"></bean>
    <bean id="bean3" class="com.eator.entity.Bean3"></bean>
</beans>

实体类:

    /**
     * @Resource 作用在属性上,默认根据属性名称去配置文件中查找对应的id来创建对象,然后赋值给变量(直接赋值不用set方法和构造方法)
     * 如果找不到对应的id,则根据属性类型去查找,如果没有对应的属性类型或着有多个则报错。
     * 注解可以指定name 属性根据指定的名称去配置文件查找对应的id,一旦指定了名称只会根据名称查找则报错。
     *  @Autowired 作用在属性上,根据默认的类型去配置文件查找对应的bean,创建对象后赋值给该属性变量。
     *  如果找不到或找到多个,则根据属性名称去查找bean,如果找不到则报错。
     *  可以配合@Qualifier注解设置value值来查找id,查不到就报错。
     *  总结:直接作用在属性上,set和get方法可以省略。
     */
public class Bean1 {
//    @Resource(name = "bean2")
    @Autowired
    @Qualifier(value = "bean2")
    private Bean2 bean2;
    @Resource
    private Bean3 bean3;
}

类注解Controller、Service、Repository、Component和Scope

 * 以下四个注解作用在类上功能相同,根据规范写在不同的地方。作用:相当于在配置文件中配置bean,id默认是根据类的首字母小写value指定id,默认单例模式。
 * @Controller  用在控制层
 * @Service     用在业务层
 * @Repository  用在数据访问层
 * @Component   除了上面三个之外的不好区分的类用这个注解
 * 
 * @Scope(value = "prototype") 使得创建对象时创建多个
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
   <!--主键包扫描,指定包以及自包路径下的所有被@Compnent @Controller @Service @Repository标注过的类,都创建对象-->
   <context:component-scan base-package="com.eator.entity"/>
</beans>

从配置文件中获取对象

public class Test {
    public static void main(String[] args) {
/*        //自己创建对象
        Student student = new Student();
        student.setId(1);
        student.setName("张三");
        student.setAge(20);
        System.out.println(student);*/

        //把对象创建工作交给Spring容器集中创建,要用的时候直接去Spring容器中去取。
        //1、加载spring配置文件,启动spring的容器,创建对象。每一分bean标签只创建一个对象,单例模式。默认加载文件时创建。
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2、从spring从容器中获取对象
        Student student = (Student)context.getBean("student");//根据id取对象
        Student s = context.getBean(Student.class);//根据类型取对象,有风险(多个则报错)。
        //3、使用对象
        System.out.println(student);
        System.out.println(student==s);

多个配置文件时获取对象

导入配置文件

创建新的xml文件(applicationContext_bean.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 http://www.springframework.org/schema/beans/spring-beans.xsd">

   <!--导入其他配置文件,按照导入顺序加载,bean的创建顺序默认根据配置的先后顺序创建对象-->
   <import resource="applicationContext.xml"></import>
   <bean id="bean1" class="com.eator.entity.Bean1"></bean>
   <bean id="bean2" class="com.eator.entity.Bean2"></bean>
   <bean id="bean3" class="com.eator.entity.Bean3" ></bean>
</beans>

获取对象

	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_bean.xml");
        Bean bean = context.getBean(Bean.class);
        Bean1 bean1 = context.getBean(Bean1.class);
        Bean2 bean2 = context.getBean(Bean2.class);
        Bean3 bean3 = context.getBean(Bean3.class);
通过占位符的方式

applicationContext*.xml 代表所有以applicationContext开头的xml文件(注意id唯一)

	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext*.xml");
	    Bean bean = context.getBean(Bean.class);
        Bean1 bean1 = context.getBean(Bean1.class);
        Bean2 bean2 = context.getBean(Bean2.class);
        Bean3 bean3 = context.getBean(Bean3.class);

使用注解Configuration替代配置文件

@Configuration 作用在类上,相当于该类是一个applicationContext.xml配置文件文件
与@Controller @Repository @Service @Component功能相同,多了一个容器的职能。

@Configuration
public class SpringConfig {
    /**
     * @Bean 此注解多用在方法中,相当于在配置中配置了一个bean标签,IOC会自动创建该对象
     */
    @Bean(initMethod = "init")//创建对象时的初始化方法。
    @Lazy//延迟加载,使用时才创建。默认是加载IOC容器就创该对象
    @Scope(value = "prototype")//每次调用创建新的对象,默认单例、
    public Bean1 bean1() {//id值为方法名,该类中的方法不能重载。
        return new Bean1();
    }

    @Bean
    public Bean2 bean2() {
//        Bean2 bean2 = new Bean2(bean3());//使用的对象是ioc创建好的对象,默认单例
        Bean2 bean2 = new Bean2(new Bean3());//使用的对象是新的对象
        return bean2;
    }

    @Bean
    public Bean2 bean22(Bean3 bean3) {//IOC容器认为参数为其他方法,首先根据参数名称找方法,找不到根据类型找,找到多个则报错。
        return new Bean2(bean3);
    }

    @Bean
    public Bean3 bean3() {
        return new Bean3();
    }
}

获取对象

加载配置类,创建类中的各个对象

public class Test2 {
    public static void main(String[] args) {
   		 //加载配置类,创建类中定义的各个对象
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Bean1 bean1 = (Bean1) context.getBean("bean1");//根据方法名获取对象
    }
}

(与上边的区别:获取包下的所有对象)
加载指定包以及子包被@Controller @Repository @Service @Configuration @Component注解过的类创建对象放入IOC容器中

public class Test2 {
    public static void main(String[] args) {
        //加载指定包以及子包被@Controller @Repository @Service @Configuration @Component注解过的类创建对象
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com");
        Bean2 bean2 = (Bean2) context.getBean("bean2");
        Bean3 bean3 = (Bean3) context.getBean("bean3");
        System.out.println(bean2);
        System.out.println(bean3);
    }
}

@Import注解的使用

@Import四种使用方法
第一种:直接导入类

自定义类
public class Bean6 {
}

导入
@Configuration
@Import({Bean6.class})
public class SpringConfig {
}

获取对象:只能通过类型和全限定名获取该对象
public class Test2 {
    public static void main(String[] args) {
    	//加载指定包以及子包被@Controller @Repository @Service @Configuration @Component注解过的类创建对象
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com");
        //通过指定类型获取对象,多个则报错
        Bean6 bean6 = context.getBean(Bean6.class);
        //通过全限定名来获取对象
        //Bean6 bean6 = (Bean6)context.getBean("com.entity.Bean6");
        System.out.println(bean6);
    }
}

第二种:导入其他配置类(类中有@Bean注解),相当于配置文件中导入其他配置文件

配置类
public class BeanConfig {
    @Bean
    public Bean7 bean7() {
        return new Bean7();
    }
}

导入
@Configuration
@Import({BeanConfig.class})
public class SpringConfig {
}

获取对象:可以根据方法名获取和根据类型获取对象,导入的方法与原有的方法相同(同类型同名称)则为一个方法。

public class Test2 {
    public static void main(String[] args) {
        //加载配置类,创建类中定义的各个对象
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //加载指定包以及子包被@Controller @Repository @Service @Configuration @Component注解过的类创建对象
        Bean7 bean2 = (Bean7)context.getBean("bean7");
        System.out.println(bean2);
    }
}

第三种:实现ImportSelector接口,可以动态添加类到ioc容器中进行创建对象

实现类
public class ImportBean implements ImportSelector {
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{Bean4.class.getName(), Bean5.class.getName()};
    }
}


导入该实现类
@Configuration
@Import({ImportBean.class})
public class SpringConfig {
}

获取对象:只能通过全限定名和类型获取
public class Test2 {
    public static void main(String[] args) {
        //加载配置类,创建类中定义的各个对象
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Bean4 bean4 = (Bean4)context.getBean("com.entity.Bean4");
        Bean5 bean5 = context.getBean(Bean5.class);
        System.out.println(bean4);
        System.out.println(bean5);
    }
}

第四种:实现ImportBeanDefinitionRegistrar接口

实现类:可以指定名称
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        registry.registerBeanDefinition("bean1", BeanDefinitionBuilder.rootBeanDefinition(Bean1.class).getBeanDefinition());
        registry.registerBeanDefinition("bean2", BeanDefinitionBuilder.rootBeanDefinition(Bean2.class).getBeanDefinition());
    }
}

导入
@Configuration
@Import({MyImportBeanDefinitionRegistrar.class})
public class SpringConfig {
}


获取对象:通过名称查询和类型查询
public class Test2 {
    public static void main(String[] args) {
        //加载配置类,创建类中定义的各个对象
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Bean1 bean1 = (Bean1)context.getBean("bean1");
        Bean2 bean2 = context.getBean(Bean2.class);
        System.out.println(bean1);
        System.out.println(bean2);
    }
}

总结

Spring是一个容器,负责创建对象(IOC)、和传对象(DI),减少了模块的耦合度,降低了程序的复杂度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值