Spring(三)——HelloSpring、IOC创建对象的方式、属性注入、自动装配、使用注解开发

1. 简介

Spring就是一个轻量级的控制反转(IOC) 和面向切面编程(AOP)的框架!
Spring目的:解决企业应用开发的复杂性

2. IOC理论推导

传统new对象的逻辑开发:
dao—>daoImpl—>service—>serviceImpl

如果用户想要切换数据库实现,所有的主动权在程序员的手上,需要修改程序。

所以要控制反转:原来程序员的主动权要交给用户;需要对外暴露接口(set方法)

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法

(1)在pom.xml 中导入junit 测试依赖

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

(2)在dao层创建接口,以及接口的实现类
在这里插入图片描述

  • UserMapper接口
package com.zz.dao;

//关于用户的接口
public interface UserMapper {
    public void getUser();
}
  • 接口的实现类UserMapperImpl
package com.zz.dao.impl;

import com.zz.dao.UserMapper;

public class UserMapperImpl implements UserMapper {

    public void getUser() {
        System.out.println("获取用户数据");
    }
}
  • 接口的实现类UserMapperMysqlImpl
package com.zz.dao.impl;

import com.zz.dao.UserMapper;

public class UserMapperMysqlImpl implements UserMapper {
    public void getUser() {
        System.out.println("Myaql获取用户数据");
    }
}

(3)同样在service层(调用dao层)创建接口,以及接口的实现类

在这里插入图片描述

  • UserService接口
package com.zz.service;
//用户业务层,本质调用dao层(获取数据),然后在业务层执行操作
public interface UserService {
    public void getUser();
}
  • 接口的实现类UserServiceImpl
package com.zz.service.impl;

import com.zz.dao.UserMapper;
import com.zz.service.UserService;

public class UserServiceImpl implements UserService {

    //调用dao层
    private UserMapper userMapper;

    //set方法 只需要对外提供接口 程序不用管理实现
    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public void getUser() {
        userMapper.getUser();
    }
}

(4)在test层,创建测试类
用户根据不同的需求进行修改测试类代码
在这里插入图片描述

  • 调用UserMapperImpl实现类的方法
    注释掉UserMapperMysqlImpl userMapper = new UserMapperMysqlImpl();这行代码即可
import com.zz.dao.impl.UserMapperImpl;
import com.zz.dao.impl.UserMapperMysqlImpl;
import com.zz.pojo.Hello;
import com.zz.pojo.Student;
import com.zz.service.impl.UserServiceImpl;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

//客户端
public class MyTest {
    @Test
    public void test1(){
        //主动权交给用户 想用就去调用接口
        UserMapperImpl userMapper = new UserMapperImpl();
        //UserMapperMysqlImpl userMapper = new UserMapperMysqlImpl();

        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserMapper(userMapper);
        userService.getUser();
    }
}

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

  • 调用UserMapperMysqlImpl实现类的方法
    注释掉UserMapperImpl userMapper = new UserMapperImpl();这行代码即可
import com.zz.dao.impl.UserMapperImpl;
import com.zz.dao.impl.UserMapperMysqlImpl;
import com.zz.pojo.Hello;
import com.zz.pojo.Student;
import com.zz.service.impl.UserServiceImpl;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

//客户端
public class MyTest {
    @Test
    public void test1(){
        //主动权交给用户 想用就去调用接口
        //UserMapperImpl userMapper = new UserMapperImpl();
        UserMapperMysqlImpl userMapper = new UserMapperMysqlImpl();

        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserMapper(userMapper);
        userService.getUser();
    }
 }

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

3. HelloSpring

项目目录:
在这里插入图片描述
(1)在pom.xml 中导入spring-webmvc依赖

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.9.RELEASE</version>
</dependency>

(2)创建实体类 Hello

package com.zz.pojo;

public class Hello {
    private String name;

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

    public void show(){
        System.out.println("Hello,"+name);
    }
}

注意:set方法必须要有

(3)在resources目录下创建配置文件applicationContext.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">
    
    <!--注册到Spring Bean就是我们的对象
    Hello hello = new Hello();
    hello.setName();
    id=对象
    name=属性
    value=属性值    
    -->  
    <bean id="hello" class="com.zz.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>
</beans>

(4)编写测试类测试

@Test
  public void test2(){
     ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     Hello hello = (Hello) context.getBean("hello");
     hello.show();
}

运行结果:
在这里插入图片描述

  • hello 对象是由Spring创建的
  • hello 对象的属性是由Spring容器设置的

4. IOC创建对象的方式

4.1 使用无参构造创建对象(默认)

实体类中需要set方法,配置文件中通过property标签注入

(1)实体类

package com.zz.pojo;

public class User {
    private String name;

    public User() {
        System.out.println("对象被创建了");
    }

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

    public void show(){
        System.out.println("name="+name);
    }
}

(2)配置文件

<bean id="user" class="com.zz.pojo.User">

        <property name="name" value="大佬"/>
</bean>

(3)测试类

 @Test
    public void test3(){
        //在加载容器时,所有bean就已经被创建了
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");
        user.show();
    }

测试结果:
在这里插入图片描述
注意:在加载容器时,所有bean就已经被创建了

4.2 使用有参构造创建对象

实体类中需要有参构造方法,配置文件中通过constructor-arg标签注入

(1)实体类

package com.zz.pojo;

public class User {
    private String name;

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

    public void show(){
        System.out.println("name="+name);
    }
}

(2)配置文件

<bean id="user" class="com.zz.pojo.User">

        <!--有参构造注入-->
        <constructor-arg name="name" value="大佬2"/>
</bean>

(3)测试类
与上面无参测试类相同

@Test
    public void test3(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");
        user.show();
    }

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

5. Spring配置

5.1 别名

<!--别名,如果添加了别名,我们也可以使用别名获取到这个对象-->
<alias name="user" alias="userNew"/>

5.2 bean的配置

id : bean 的唯一标识符,也就是相当于我们学的对象名
class : bean 对象所对应的全限定名 : 包名 + 类型
name :也是别名,而且name 可以同时取多个别名

<bean id="user" name="user3 user4 user5" class="com.zz.pojo.User">

5.3 import标签

import一般用于团队开发使用,他可以将多个配置文件,导入合并为一个。

在applicationContext.xml文件中有如下代码,而没有Bean的配置

 <import resource="spring-dao.xml"/>

Bean的配置写在spring-dao.xml文件中

<bean id="user" class="com.zz.pojo.User">
        <constructor-arg name="name" value="大佬2"/>
</bean>

依然可以获取user对象,测试成功。

6. 属性注入

(1)创建实体类 Address 和Student

package com.zz.pojo;

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 + '\'' +
                '}';
    }
}
package com.zz.pojo;

import java.util.*;

public class Student {

    private String name;
    private Address address;
    private String[] books;
    private List<String> list;
    private Map<String,String> map;
    private Set<String> set;
    private String wife;  //null
    private Properties info;

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

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

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

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

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

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

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

(2)配置文件student.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="addr" class="com.zz.pojo.Address">
     <property name="address" value="安徽"/>
 </bean>


<bean id="student" class="com.zz.pojo.Student">
    <!--常量注入-->
    <property name="name" value="大佬"/>

    <!--引用类型 是对象用ref-->
    <property name="address" ref="addr"/>

    <!--数组类型-->
    <property name="books">
        <array>
            <value>语文</value>
            <value>数学</value>
            <value>英语</value>
        </array>
    </property>

    <!--list类型-->
    <property name="list">
        <list>
            <value>list1</value>
            <value>list2</value>
        </list>
    </property>

    <!--map类型-->
    <property name="map">
        <map>
            <entry key="k1" value="v1"/>
            <entry key="k2" value="v2"/>
        </map>
    </property>

    <!--set类型-->
    <property name="set">
        <set>
            <value>set1</value>
            <value>set2</value>
        </set>
    </property>

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

    <!--properties类型-->
    <property name="info">
        <props>
            <prop key="id">001</prop>
            <prop key="name">zz</prop>
        </props>
    </property>

</bean>
    
</beans>

(3)测试类 MyTest

 @Test
    public void test4(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
    }

测试结果:
在这里插入图片描述
bean的作用域:scope属性
singleton:单例,容器中只存心一个对象(默认)
prototype:非单例,每次创建新对象

<bean id="student" class="com.zz.pojo.Student" scope="prototype">

其余的 request、session、application这些只能在web开发中使用到。

7. 自动装配

手动装配:一个个赋值
自动装配:自动化赋值,不需要一个个赋值

7.1 测试环境搭建

一个人有两个宠物
(1)在java目录下,创建entity包,包下创建三个实体类User、Cat、Dog

package com.zz.entity;

public class Cat {
    public void shout(){
        System.out.println("miao...");
    }
}
package com.zz.entity;

public class Dog {
    public void shout(){
        System.out.println("wang...");
    }
}
package com.zz.entity;

public class User {

    private String name;
    private Cat cat;
    private Dog dog;

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

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

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

    public String getName() {
        return name;
    }

    public Cat getCat() {
        return cat;
    }

    public Dog getDog() {
        return dog;
    }

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

7.2 byName自动装配

autowire="byName"会自动在容器上下文中查找,和自己对象set方法后面的值对应的 bean id

所以下列代码中,手动配置的那两行可以注释掉

user.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">

    <!--cat和dog都是引用类型,且没有属性-->
    <bean id="cat" class="com.zz.entity.Cat"/>
    <bean id="dog" class="com.zz.entity.Dog"/>


    <!--自动配置-->
    <bean id="user" class="com.zz.entity.User" autowire="byName">
        <property name="name" value="大佬"/>
        <!--<property name="cat" ref="cat"/>-->
        <!--<property name="dog" ref="dog"/>-->
    </bean>

</beans>

MyTest测试类:

@Test
    public void test5(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");
        System.out.println(user);
        user.getCat().shout();
        user.getDog().shout();        
    }

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

7.3 byType自动装配

autowire="byType"会自动在容器上下文中查找,和自己对象属性类型相同的bean

只将上述代码中autowire="byName"改为autowire=“byType”,其余代码均与上面相同,测试结果也相同

但是如果这个类型有多个bean,就会报错

小结:

  • byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
  • bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!
  • 在真实的开发中,我们不这么用,而是使用注解实现自动配置

7.4 使用注解实现自动装配

要使用注解须知:

在applicationContext.xml中

  • 导入约束 : context约束
    xmlns:context=“http://www.springframework.org/schema/context”
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd">

  • 配置注解的支持 : context:annotation-config/

添加后,完整的applicationContext.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"
    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/>
    <import resource="user.xml"/>

</beans>

(1)@Autowired注解

  • 直接在属性上使用即可!也可以在set方式上使用!
  • 使用Autowired 我们可以不用编写Set方法了,前提是你这个自动装配的属性在 IOC(Spring)容器中存在,且符合名字byname!

User类中删除了setCat和setDog方法,添加了@Autowired注解:

package com.zz.entity;

import org.springframework.beans.factory.annotation.Autowired;

public class User {

    private String name;
    @Autowired  //自动装配
    private Cat cat;
    @Autowired
    private Dog dog;

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


    public String getName() {
        return name;
    }

    public Cat getCat() {
        return cat;
    }

    public Dog getDog() {
        return dog;
    }

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

user.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">

    <!--cat和dog都是引用类型,且没有属性-->
    <bean id="cat" class="com.zz.entity.Cat"/>
    <bean id="dog" class="com.zz.entity.Dog"/>

    <!--自动配置-->
    <bean id="user" class="com.zz.entity.User">
        <property name="name" value="大佬"/>

    </bean>
</beans>

测试类不变,依然能测出相同的结果
在这里插入图片描述
科普:@Nullable 字段标记了这个注解,说明这个字段可以为null;

(2)@Resource注解

public class People {

    @Resource(name = "cat2")
    private Cat cat;

    @Resource
    private Dog dog;
    
}

小结:
@Resource 和@ Autowired 的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @ Autowired 通过byType的方式实现,而且必须要求这个对象存在! 【常用】
  • @ Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错! 【常用】
  • 执行顺序不同:@ Autowired 通过byType的方式实现。@ Resource 默认通过byname的方式实现

8. 使用注解开发

(1)在Spring4之后,要使用注解开发,必须要保证 aop的包导入了
在这里插入图片描述
(2)使用注解需要导入context约束,增加注解的支持!
applicationContext.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"
       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.zz.pojo"/>

</beans>

不用再编写people.xml 文件,不用进行bean标签之类的配置

(3)实体类People:

@Component(“people”) 相当于 : < bean id=“people” …/>
@Value("大哥”)相当于: < property name=“name” value=“大哥”/>
@Scope(“prototype”) 表示作用域,也分为原型模式prototype和单例模式singleton

package com.zz.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("people")
@Scope("prototype")
public class People {
    @Value("大哥")
    public String name;

    //也可以放在set方法上
   // @Value("大哥2")
    public void setName(String name) {
        this.name = name;
    }
}

(4)测试类:

@Test
    public void test6(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        People people = (People) context.getBean("people");
        System.out.println(people.name);
    }

测试结果:
在这里插入图片描述
衍生的注解

@Component 有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!

  • dao 【@Repository】

  • service 【@Service】

  • controller 【@Controller】

    这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean

小结:
xml 与 注解:

  • xml 更加万能,适用于任何场合!维护简单方便
  • 注解 不是自己类使用不了,维护相对复杂!

xml 与 注解最佳实践:

  • xml 用来管理bean;
    如: < bean id=“student” class=“com.zz.pojo.Student”/>
  • 注解只负责完成属性的注入;
    如:@Value(“小明”)
    private String name;
  • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
发布了62 篇原创文章 · 获赞 2 · 访问量 2717

猜你喜欢

转载自blog.csdn.net/nzzynl95_/article/details/104463657