Spring Ioc

53 阅读7分钟

spring入门的使用

在一个完整的业务中,我们有dao层和service层,controller层 先实现一个完整的业务逻辑

实现dao层

package com.sheng.dao;

public interface UserDao {
    void getUser`();`
}

实现dao层的接口实现类

package com.sheng.dao;

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

实现service接口(接口与dao层接口一样)

package com.sheng.service;

public interface UserService {
    void getUser();
}

实现service的接口实现(调用dao层)

package com.sheng.service;

import com.sheng.dao.UserDao;
import com.sheng.dao.UserDaoImpl;
import com.sheng.dao.UserDaoMysqlImpl;
import com.sheng.dao.UserDaoSqlServiceImpl;

public class UserServiceImpl implements UserService{

    private UserDao userDao=new UserDaoImpl();

    
    //业务层去调用dao层
    public void getUser() {
        userDao.getUser();
    }
}

实现controller层(这里用test测试来替代)

import com.sheng.dao.UserDaoImpl;
import com.sheng.dao.UserDaoMysqlImpl;
import com.sheng.dao.UserDaoSqlServiceImpl;
import com.sheng.service.UserService;
import com.sheng.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
//        用户实际调用的是业务层,dao层不需要接触!
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(new UserDaoImpl());
        userService.getUser();

    }
}

那么运行结果如下

image.png

倘若我现在要获取mysql用户数据,怎么实现?普通方法是

实现dao层接口实现类

package com.sheng.dao;

public class UserDaoMysqlImpl implements UserDao{
    public void getUser() {
        System.out.println("msyql获取用户数据库");
    }
}

service接口不变

service接口实现类

package com.sheng.service;

import com.sheng.dao.UserDao;
import com.sheng.dao.UserDaoImpl;
import com.sheng.dao.UserDaoMysqlImpl;
import com.sheng.dao.UserDaoSqlServiceImpl;

public class UserServiceImpl implements UserService{

    private UserDao userDao=new UserDaoMysqlImpl();


    //业务层去调用dao层
    public void getUser() {
        userDao.getUser();
    }
}

注意,service实现类中,我的userdao对象从UserDaoImpl变成了UserDaoMysqlImpl,因为我现在要实现的是获取mysql用户数据,dao'层的对象肯定要变。

实现结果 image.png

倘若我要实现sqlservice的数据,是不是要查询实现dao层,service再更换对象?

发现是不是特别麻烦,你要频繁的根据用户的需求去更换不同的对象,那我们怎么样能简化啊实现?其实很简单

以上所有代码均不变,service接口的实现类改变一下

package com.sheng.service;

import com.sheng.dao.UserDao;
import com.sheng.dao.UserDaoImpl;
import com.sheng.dao.UserDaoMysqlImpl;
import com.sheng.dao.UserDaoSqlServiceImpl;

public class UserServiceImpl implements UserService{

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    //业务层去调用dao层
    public void getUser() {
        userDao.getUser();
    }
}

发现什么区别没有,再之前,我是在service的实现类中,直接new的指定对象,但现在我只是声明,但我没有去创造 那我什么时候创造?当然是你要的时候我去创造,再看我们的实现类有什么变化?

import com.sheng.dao.UserDaoImpl;
import com.sheng.dao.UserDaoMysqlImpl;
import com.sheng.dao.UserDaoSqlServiceImpl;
import com.sheng.service.UserService;
import com.sheng.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
//        用户实际调用的是业务层,dao层不需要接触!
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(new UserDaoSqlServiceImpl());
        userService.getUser();

    }
}

在实现获取user信息之前,我先调用setuserdao,因为我要知道你要实现的是什么业务吧,你要什么业务,你就在setuserdao中创建谁的对象就好,哎嘿,这种就把创建对象的操作交给了用户。

举一个小例子(自己想象的,可以跳过):

你是一家商店的老板,客户来了,他想要买烟,你去烟柜台去拿,他要买水,你又要去水柜台去拿,拿了之后,客户说我不要了,我要可乐,那你又回去帮他换瓶可乐。你是不是总是被客户牵着鼻子走,你不烦,我都烦了,于是啊,你想,你把柜台直接放在外面,客户来了,哎嘿,你要啥,自己去拿去,你要换啥,自己去换去,把控制权交给了用户,那么老板你列,当然是安心扩充自己的业务去啦!

以上我们用指定创建对象,变成了set注入,而set注入就是实现ioc的一种方式

这是我们最原生的业务实现方式,耦合性很高,层层嵌套

那么我们怎么用spring ioc来实现?

很简单,只需要一个配置文件即可,在resources下创建一个beans.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="UserDaoMysqlImpl" class="com.sheng.dao.UserDaoMysqlImpl">

   </bean>
    <bean id="UserDaoSqlServiceImpl" class="com.sheng.dao.UserDaoSqlServiceImpl">

    </bean>

    <bean id="UserServiceImpl" class="com.sheng.service.UserServiceImpl">
        <!--
        rel:是引用spring容器中创建好的对象
        value:具体的值,基本数据类型;
        -->
        <property name="userDao" ref="UserDaoMysqlImpl"></property>
    </bean>
</beans>

以上就是一个简单的spring ioc的配置文件 再业务原生方法中,我们会有很多上面介绍到的坏处,对象由我们来创建,

而spring ioc是怎么来处理的,以前是我来创建对象,现在是由ioc来创建对象 什么意思?就是把我们的类交给IOC容器,我们把类型的业务实现好就可以不用管了,用户要实现什么业务,我们要去找serivce的对象,现在直接去ioc里面去找就可以了,因为我把这些权力都给了ioc,

阅读上方的xml文件,想要把对象交给IOC容器,我们需要用到xml中的bean标签,id就为我们的类名,class就是我们类的全路径,类中必然有参数的情况,bean中property标签name属性就是我们类中的属性名,value参数可以为我们类中的属性赋值

用了配置文件后,我们就轻便多了 在test测试类中

import com.sheng.dao.UserDaoImpl;
import com.sheng.dao.UserDaoMysqlImpl;
import com.sheng.dao.UserDaoSqlServiceImpl;
import com.sheng.service.UserService;
import com.sheng.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
//        用户实际调用的是业务层,dao层不需要接触!
//        UserServiceImpl userService = new UserServiceImpl();
//        userService.setUserDao(new UserDaoSqlServiceImpl());
//        userService.getUser();

        //获取ApplicationContext,拿到spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //容器在手,天下我有,需要什么就get
        UserServiceImpl userServiceImpl = (UserServiceImpl)context.getBean("UserServiceImpl");
        userServiceImpl.getUser();

    }
}

原来的实现方式就可以注了,

我们只需要通过

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

来读取到我们的bean.xml文件,这样才能获取到参数 有了这个配置文件后,他肯定会读取到我们xml里面的bean,那么多bean,我要用那个? 需要通过

UserServiceImpl userServiceImpl = (UserServiceImpl)context.getBean("UserServiceImpl");

通过读取到配置文件的对象去getBean,你要实现那个业务就获取那个bean id,也就是那个类,你从bean中获取那个类,你就能得到那个类,有了这个类,我就能调用他的方法,然后getUser,这个没什么好说的

需要强调的是bena中的property,因为我们在一个类,会有参数,也会对象作为参数的时候,比如如上

private UserDao userDao;

我们在service中,把dao层作为对象 这个时候我们的property的value就不能用了,应该改为rel,而rel'就指向该类的bean id即可

不同的bena.xml可以相互引用

<import resource="beans.xml"></import>

在当前的bean.xml resource到你想引用的bean.xml即可

接下来给大家说说bean中参数的问题

创建一个实体类(Student)

package com.sheng.pojo;

import java.util.*;

public class Student {
    private String name;
    private Address address;
    private String[] book;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", address=" + address.toString() +
                ", book=" + Arrays.toString(book) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + ''' +
                ", info=" + 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[] getBook() {
        return book;
    }

    public void setBook(String[] book) {
        this.book = book;
    }

    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;
    }
}
package com.sheng.pojo;

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

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

咱们看看这个Student类,利用不同的类型的数据作为参数,那么这个时候我们在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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    bean的作用域
        scope:singletion ;默认为单列模式
              prototype:为原型模式 每次从容器中get的时候,都会产生一个新的对象
              其他的·request,session,application,这些只能在web开发中使用到
            -->
    <bean id="address" class="com.sheng.pojo.Address">
        <property name="address" value="霍去病"></property>
    </bean>
    <bean id="student" class="com.sheng.pojo.Student">
<!--        第一种,普通值注入,value-->
        <property name="name" value="徐长卿"></property>
<!--        第二种,bean注入,rel-->
        <property name="address" ref="address"></property>
<!--        第三种,数组注入-->
        <property name="book" >
            <array>
                <value>西游记</value>
                <value>水浒传</value>
                <value>红楼梦</value>
                <value>三国演义</value>
            </array>
        </property>
<!--        list-->
        <property name="hobbys">
            <list>
                <value>听哥</value>
                <value>打球</value>
            </list>
        </property>
<!--        map-->
        <property name="card">
            <map>
                <entry key="身份证" value="123"/>
                <entry key="银行卡" value="2222"/>
            </map>
        </property>
<!--        set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>cf</value>
                <value>bob</value>
            </set>
        </property>
<!--        null-->
        <property name="wife">
            <null></null>
        </property>
<!--        Properties-->
        <property name="info">
            <props>
                <prop key="学号">2020112918</prop>
                <prop key="系别"></prop>
            </props>
        </property>
    </bean>
</beans>

每一个类型的赋值方式如上,自己可以在底下试试

Spring注解

我们会发现随着我们的类越来越多,我们在xml中加入的bean也就越多,这种情况,我们的注解就出现了

我们在开发中有不同层的实现类,我们在注解中也有区分

  1. @Controller 代表它是一个Controller层的类,在类上加上这个注解功能就相当余在xmlbean了这个类 2.@Repository 代表它是一个dao层类 3.@Component 代表它是一个实体类 4.@Service 代表是一个service层的类

通过注解,我们就可以舍弃xml的方式,两种方式,那么喜欢那种就用那种

注意的是,写上了注解我们还不能用,因为我们要激活它

<context:annotation-config/>

激活注解之后我们还是不能用,嘿嘿嘿,因为我们要进行一次扫描,让容器知道有那些类要当ioc容器中去

<context:component-scan base-package="com.sheng"/>

加上以上两行代码在bean.xml即可,注意base-package的值是你要扫描的包

对于注解的补充

以上四个注解实现的功能都是一样的,主要是为了区分不同的业务层 以@Component举例 @Component("name")等于@Component(value="user") 给当前类的beanid取为user

@Value注解,放在字段上,默认值就为@value("")

@Value("徐长卿")  //等价于<property name="" value=""/>
public String name;

@Resource注解 在类中我们会存在字段是一个对象的情况,

@Resource(name = "user")
private User user;

需要用到resource来声明,