Spring框架-控制反转(IoC)

1.Spring框架-控制反转

1.1spring简介:

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心就是一个轻量级的控制反转(IoC)和面向切面(AOP)的框架!

1.2spring特点:
  • Spring是一个开源的免费的框架(容器)
  • Spring是一个轻量级的、非入侵式的框架
  • 控制反转(IOC) , 面向切面编程(AOP)
  • 支持事务的处理,Spring提供了一致的事务管理接口,可向下扩展到(使用一个单一的数据库,例如)本地事务并扩展到全局事务(例如,使用 JTA)。
  • 降低API开发难度对JavaEEAPI(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
  • 对框架整合的支持
1.3spring组成

在这里插入图片描述

2.hellospring

2.1导入spring相关的jar包
 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <!-- 单元测试jar包-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
 </dependency>
2.2具体项目场景
Dao层接口及实现类

UserDao接口

public interface UserDao {
    
    
    public void getUser();
}

UserDao接口的多个实现类

public class UserDaoImpl implements UserDao {
    
    
    public void getUser() {
    
    
        System.out.println("获取默认数据!");
    }
}

public class UserDaoMysqlImpl  implements UserDao{
    
    
    public void getUser() {
    
    
        System.out.println("获取Mysql的数据!");
    }
}

public class UserDaoOracleImpl implements UserDao {
    
    
    public void getUser() {
    
    
        System.out.println("获取Oracle的数据!");
    }
}

public class UserDaoServerImpl implements UserDao {
    
    
    public void getUser() {
    
    
        System.out.println("获取Server的数据!");
    }
}
service层接口及实现类

UserService 接口

public interface UserService {
    
    
    public void getUser();
}

UserServiceImpl实现类

public class UserServiceImpl implements UserService {
    
    
    private UserDao userDao;
    public void setUserDao(UserDao userDao){
    
    
        this.userDao = userDao;
    }
    public void getUser() {
    
    
        userDao.getUser();
    }
}
配置文件

spring容器创建对象、设置属性。

<?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    对象名
class 实例的全限定类名
-->
<bean id="userService" class="com.li.service.UserServiceImpl"/>
</beans>
测试
public class MyTest {
    
    
    @Test
    public void test() {
    
    
        //获得spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获得需要的对象
        UserServiceImpl userService = context.getBean("userService", UserServiceImpl.class);
        //需要使用那个类就创建  
        userService.setUserDao(new UserDaoMysqlImpl());
        userService.getUser();
    }
}

3.spring配置

配置文件

<?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="user" class="com.li.pojo.User">
    property name="name" value="小明"/>
  </bean>
 <!-- Spring的配置说明-->
    <!--alias  别名的设置 -->
    <alias name="user" alias="newuser"></alias>
<!-- bean的配置 name可以是多个中间的符号可以是分号空格逗号-->
  <bean id="user" class="com.li.pojo.User" name="u2;u3 u4,u6">
    <property name="name" value="小明"/>
  </bean>

<!-- import 多个配置导入合成一个-->
</beans>

4.依赖注入(构造器、setter、其它)

4.1构造器注入
实体类
public class User {
    
    
    private String name;
    public User(){
    
    
       System.out.println("User的无参构造");
    }
    public User(String name){
    
    
        this.name= name;
    }
    public String getName(){
    
    
        return name;
    }
    public void setName(String name){
    
    
        this.name = name;
    }
    public void show() {
    
    
        System.out.println("name="+name);
    }
}
配置文件
<?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">
    <!--IOC创建对象的方式 当配置文件bean标签创建的时候 User已经被实例化了
    -->
    <!-- 使用无参构造创建对象 默认!-->
    <bean id="user" class="com.li.pojo.User">
    <property name="name" value="小明"/>
    </bean>
<!-- 有参构造创建对象的三种方式-->
    <!-- 方式一:通过索引赋值-->
    <bean id="user" class="com.li.pojo.User">
    <constructor-arg index="0" value="小红"/>
    </bean>

    <!-- 方式二:通过参数类型匹配 多个参数不推荐使用-->
    <bean id="user" class="com.li.pojo.User">
    <constructor-arg type="java.lang.String" value="开心"/>
    </bean>

    <!-- 方式三:通过name 进行赋值-->
    <bean id="user" class="com.li.pojo.User" name="u5">
        <constructor-arg name="name" value="欢喜"/>
    </bean>

 </bean>

4.2 set注入
实体类(模拟所有的set注入方式)
public class Student {
    
    
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Address getAddress() {
    
    
        return address;
    }

    public void setAddress(Address address) {
    
    
        this.address = address;
    }

    public String[] getBooks() {
    
    
        return books;
    }

    public void setBooks(String[] books) {
    
    
        this.books = books;
    }

    public List<String> getHobbys() {
    
    
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
    
    
        this.hobbys = hobbys;
    }

    public Map<String, String> getCard() {
    
    
        return card;
    }

    public void setCard(Map<String, String> card) {
    
    
        this.card = card;
    }

    public Set<String> getGames() {
    
    
        return games;
    }

    public void setGames(Set<String> games) {
    
    
        this.games = games;
    }

    public String getWife() {
    
    
        return wife;
    }

    public void setWife(String wife) {
    
    
        this.wife = wife;
    }

    public Properties getInfo() {
    
    
        return info;
    }

    public void setInfo(Properties info) {
    
    
        this.info = info;
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.toString() +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }
}

   //Address实体类 
public class Address {
    
    
    private String address;

    public String getAddress() {
    
    
        return address;
    }

    public void setAddress(String address) {
    
    
        this.address = address;
    }

    @Override
    public String toString() {
    
    
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
配置文件
<?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="address" class="com.li.pojo.Address">
        <property name="address" value="西安"/>
    </bean>

<bean name="student" class="com.li.pojo.Student">
    <!-- 注入方式:-->
    <!-- 普通注入-->
    <property name="name" value="李瑞"/>

    <!--bean注入 主要是应用类型的属性-->
    <property name="address" ref="address"/>

    <!--数组注入 -->
    <property name="books">
        <array>
            <value>英语四级</value>
            <value>英语六级</value>
            <value>计算机二级</value>
        </array>
    </property>

    <!-- List注入 -->
    <property name="hobbys">
        <list>
            <value>敲代码</value>
            <value>听音乐</value>
            <value>打篮球</value>
        </list>
    </property>

    <!-- Map注入 -->
    <property name="card">
        <map>
            <entry key="身份证" value="789456123456454658"/>
            <entry key="银行卡" value="1321312314564454"/>
        </map>
    </property>

    <!-- set注入 -->
    <property name="games">
        <set>
            <value>和平精英</value>
            <value>王者荣耀</value>
            <value>球球作战</value>
        </set>
    </property>

    <!-- null注入 -->
    <property name="wife">
        <null/>
    </property>

    <!-- properties注入 -->
    <property name="info">
        <props>
            <prop key="学号">20183306</prop>
            <prop key="宿舍号">12号楼226</prop>
        </props>
    </property>
</bean>
</beans>
测试
Student{name='李瑞', 
address=Address{address='西安'}, 
books=[英语四级, 英语六级, 计算机二级], 
hobbys=[敲代码, 听音乐, 打篮球], 
card={身份证=789456123456454658,
 银行卡=1321312314564454}, 
 games=[和平精英, 王者荣耀, 球球作战], 
 wife='null', 
 info={学号=20183306, 宿舍号=12号楼226}}
4.3其它注入
实体类
package com.li.pojo;

/**
 * @Author: Lenovo
 * @CreateTime: 2020-05-27 17:48
 * @Description:西部开源教育科技有限公司
 */
public class User {
    
    
    private String name;
    private int age;

    public User() {
    
    
    }

    public User(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName(){
    
    
        return name;
    }
    public void setName(String name){
    
    
        this.name = name;
    }
    public int getAge(){
    
    
        return age;
    }
    public void setAge(int age){
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

配置文件
<?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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- p、c命名空间需要导入各自xml约束 -->
<!--xmlns:p="http://www.springframework.org/schema/p"-->
<!--xmlns:c="http://www.springframework.org/schema/c"-->
    <bean id="user" class="com.li.pojo.User" p:name="小华" p:age="18"/>

    <bean id="user2" class="com.li.pojo.User" c:name="小李" c:age="20"/>

</beans>
4.4 bean作用域

bean作用域主要是singleton(单例模式)、prototype、web层面(request、session application、websocket)。

先看看单例模式实现方式

public class Singleton {
    
    
    //构造方法私有化,防止其他类实例化给对象
    private Singleton(){
    
    

    }
    //创建 静态的 唯一的 全局的对象
    private static Singleton singleton = new Singleton();
    //定义公开的静态方法
    public static Singleton getSingleton(){
    
    
        return singleton;
    }

    public static void main(String[] args) {
    
    
        for (int i = 0; i < 5; i++) {
    
    
            System.out.println(Singleton.getSingleton());
        }
        System.out.println("===========================");
        for (int i = 0; i < 5; i++) {
    
    
            Singleton singleton = new Singleton();
            System.out.println(singleton);
        }

    }
}

测试:在这里插入图片描述

<?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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.li.pojo.User" p:name="小华" p:age="18" scope="singleton"/>

    <bean id="user2" class="com.li.pojo.User" c:name="小李" c:age="20" scope="prototype"/>
</beans>

测试:

 @Test
    public void test2(){
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
        User user = context.getBean("user",User.class);
        User user2 = context.getBean("user", User.class);
        System.out.println(user.hashCode());//265119009
        System.out.println(user2.hashCode());//265119009
        System.out.println(user == user2);//true
    }
   public void test2(){
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
        User user = context.getBean("user2",User.class);
        User user2 = context.getBean("user2", User.class);
        System.out.println(user.hashCode());//1988859660
        System.out.println(user2.hashCode());//1514160588
        System.out.println(user == user2);//false
    }

结论
singleton作用域:创建bean的时候对象已经被实例了,并且只有一个对象
prototype作用域:每次去容器取得对象都不同。

5.Bean的自动装配

场景:一个人有两个宠物!

public class People {
    
    
    public Dog dog;
    public Cat cat;
    public String name;

    public Dog getDog() {
    
    
        return dog;
    }

    public void setDog(Dog dog) {
    
    
        this.dog = dog;
    }

    public Cat getCat() {
    
    
        return cat;
    }

    public void setCat(Cat cat) {
    
    
        this.cat = cat;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "People{" +
                "dog=" + dog +
                ", cat=" + cat +
                ", name='" + name + '\'' +
                '}';
    }
}

public class Dog {
    
    
    public void shout(){
    
    
        System.out.println("wang~");
    }
}

public class Cat {
    
    
    public void shout(){
    
    
        System.out.println("miao~");
    }
}


测试:

public class MyTest {
    
    
        @Test
        public void test() {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        People people = context.getBean("people", People.class);
        people.getCat().shout();
        people.getDog().shout();

    }
}

5.1 自动装配前:
<!--
如果类的属性中有引用类型需要使用ref标签引用
byName、 byType 可以简化xml代码不用ref标签
-->
 <bean id="cat" class="com.li.pojo.Cat"/>
    <bean id="dog" class="com.li.pojo.Dog"/>
    <bean id="people" class="com.li.pojo.People">
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
 </bean>
5.2 自动装配后:
<!-- byType就是bean的class类型 id也就是对象名随意,没有id也可以-->
    <bean  class="com.li.pojo.Cat"/>
    <bean  class="com.li.pojo.Dog"/>
    <bean  class="com.li.pojo.People" autowire="byType">
    </bean>

<!--byName根据id寻找  寻找bean中的peopel对象 -->
    <bean id="cat" class="com.li.pojo.Cat"/>
    <bean id="dog" class="com.li.pojo.Dog"/>
    <bean id="people" class="com.li.pojo.People" autowire="byName">
    </bean>

注意点:com.li.pojo.dog 的合格 bean 可用只能匹配单个bean 简单说:就是cat、dog的id名只能有一个,否则报错. Could not autowire. There is more than one bean of 'Dog' type. Beans: dog,dog2. Properties: 'dog' less... (Ctrl+F1) Inspection info:Checks autowiring problems in a Spring bean defined in XML context

6.注解开发

使用注解需要扫描指定的包,注解才可以使用

<?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
       https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <!--指定扫描的包注解可以使用-->
    <context:annotation-config/>
    <context:component-scan base-package="com.li"/>
</beans>

注解:就是一个类,使用@注解名称
开发中:使用注解 取代 xml配置文件。

  1. @Component 位置:取代 类上
    <bean id="user" class="com.li.pojo.User"/>
  2. web开发,提供3个@Component注解衍生注解(功能一样)
    @Repository :dao层 位置:类上
    @Service:service层 位置:类上
    @Controller:web层 位置:类上
  3. 依赖注入,给属性设值,使用setter注入
    普通值: @Value("") 位置:属性上
    @Value("小李")
    public String name;

引用值:
@Autowired 位置:属性、set方法上 使用@Autowired也可以不写set方法

    @Autowired
    public Dog dog;
    @Autowired
    public Cat cat;

@Resource 位置:属性

    @Resource
    public Dog dog;
    @Resource
    public Cat cat;

@Autowired 与@Resource可以解决byName 、byType只能匹配单个bean的困扰,也就是说可以引用多个bean,如果没有符合的id会直接通过类寻找

 <bean id="cat" class="com.li.pojo.Cat"/>
    <bean id="cat22" class="com.li.pojo.Cat"/>
    <bean id="cat44" class="com.li.pojo.Cat"/>
    <bean id="dog" class="com.li.pojo.Dog"/>
    <bean id="dog33" class="com.li.pojo.Dog"/>
    <bean id="people" class="com.li.pojo.People">
 </bean>

如果想要指定唯一的一个id匹配就使用@Qualifier(value=" ")或者 @Resource(name = " ")

    //方式一:	
    @Autowired
    @Qualifier(value = "dog33")
    public Dog dog;
    @Autowired
    @Qualifier(value = "cat22")
    public Cat cat;
	//方式二:
   @Resource(name = "dog33")
    public Dog dog;
    @Resource(name = "cat22")
    public Cat cat;

作用域:
@Scope("singleton") 单例模式 IOC容器启动会调用方法创建对象放到IOC容器中。以后每次获取就是直接从容器(理解成从map.get对象)中拿bean
@Scope("prototype")多例模式 IOC容器启动并不会去调用方法创建对象放在容器中,而是 每次获取的时候才会调用方法创建对象

7.基于Java的容器配置

前面的配置文件都是基于applicationContext.xml文件。现在可以通过java实现容器的配置。具体的配置如下。

7.2 实体类
@Component//相当于xml文件中bean标签
public class User {
    
    
    @Value(value = "小米")
    private String name;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

}
7.配置文件

UserConfig 类等效于以下Spring XML:
<beans> <bean id="user" class="com.li.pojo.User"/> </beans>

@Bean注释被用于指示一个方法实例,可以配置,并初始化到由Spring IoC容器进行管理的新对象

@ComponentScan(basePackages = "com.li.pojo") 等效
<beans>
    <context:component-scan base-package="com.li.pojo"/>
</beans>
// @Configuation等价于<Beans></Beans>
//@Bean等价于<Bean></Bean>
@Configuration
@ComponentScan(basePackages = "com.li.pojo")
public class UserConfig {
    
    
    @Bean//相当于bean标签
    //方法名就是id
    //方法返回值就是class属性
    public User getUser(){
    
    
        return new User();//返回的对象
    }
}
7.3测试
public class MyTest {
    
    
    @Test
    public void test(){
    
    
        //AnnotationConfigApplicationContext(UserConfig.UserConfig) 获取spring容器
        ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
        User getUser = context.getBean("getUser", User.class);
        System.out.println(getUser.getName());
    }
}

猜你喜欢

转载自blog.csdn.net/lirui1212/article/details/106393111