目录标题

  • 一、Spring简单介绍
  • 1.1、Spring框架的作用
  • 1.2、了解
  • 1.3、优点
  • 二、控制反转(IOC)
  • 2.1、何为控制反转
  • 2.2、程序主动创建类对象(原来的方式)
  • 2.3、使用IOC的设计思想(革命性改变)
  • 2.4、IOC的本质
  • 2.5、第一个Spring程序
  • 2.6、IOC创建对象的方式
  • 三、Spring配置说明
  • 3.1、bean标签
  • 3.2、alias标签
  • 3.3、import标签
  • 3.4、bean的作用域
  • 四、依赖注入
  • 4.1、通过构造器注入
  • 4.2、一般的注入方式(set方法注入)
  • 4.3、拓展注入
  • 五、bean的自动装配
  • 5.1、Spring中bean的装配方式
  • 六、使用java来配置Spring(先放放)
  • 七、面向切面编程(AOP)


一、Spring简单介绍

1.1、Spring框架的作用
  • 它的理念就是为了解决软件开发的复杂性,实现有的技术能够更加容易使用
  • 它的出现给软件行业带来了“春天”
1.2、了解
  • SSH:Struts2+Spring+Hibernate(反正我在校期间,就学的这套)
  • SSM:SpringMVC+Spring+Mybatis
1.3、优点
  • Spring是一个开源免费的框架,也可以说是一个容器,可以把什么“东西”都可以放进去(“大杂烩”)
  • Spring是一种轻量级、非入侵式的框架(非入侵式就是可以在里面随意导入任何项目)
  • 最重要的两个特性:控制反转(IOC)、面向切面编程(AOP)
  • 支持对事务的处理和对框架的整合

二、控制反转(IOC)

2.1、何为控制反转
  • 控制反转IoC(Inversion of Control),它是一种设计思想
  • 控制反转就是由原来的的程序主动创建类对象,转变为程序被动创建类对象(可能不太好理解)
    下面给出一个例子:
2.2、程序主动创建类对象(原来的方式)

通过这个例子,我们可以发现:如果按照传统的编程设计思想,那么如果用户的业务需求发生了改变,会出现一种情况:
需要在service业务层的接口实现类里面去进行再次更改,来创建新的Dao层接口实现类对象,比如:(这里可能不太好理解)

private UserDao userDao = new UserDaoImpl();
private UserDao userDao = new UserDaoMysqlImpl();

开源用户中心 spring spring 开源协议_intellij-idea

  • dao层
//Dao层接口
package com.my.dao;

public interface UserDao {
    void getUser();
}
//Dao层接口实现类
package com.my.dao;

public class UserDaoImpl implements UserDao{

    public void getUser() {
        System.out.println("默认获取用户数据!");
    }
}
//Dao层接口实现类
package com.my.dao;

public class UserDaoMysqlImpl implements UserDao{
    public void getUser(){
        System.out.println("Mysql获取用户数据");
    }
}
  • service层
//业务层接口
package com.my.service;

public interface UserService {
    void getUser();
}
package com.my.service;
import com.my.dao.UserDao;
import com.my.dao.UserDaoImpl;
import com.my.dao.UserDaoMysqlImpl;
import com.my.dao.UserDaoOracleImpl;

public class UserServiceImpl implements UserService{
    private UserDao userDao = new UserDaoImpl();
//    private UserDao userDao = new UserDaoMysqlImpl();
//    private UserDao userDao = new UserDaoOracleImpl();
    public void getUser(){
        userDao.getUser();
    }
}
  • 测试
import com.my.dao.UserDaoOracleImpl;
import com.my.service.UserService;
import com.my.service.UserServiceImpl;

public class MyTest {

    public static void main(String[] args) {
        //用户实际上调用的是业务层,dao层用户不需要接触
        UserService userService = new UserServiceImpl();
        userService.getUser();
    }
}
2.3、使用IOC的设计思想(革命性改变)

在上述例子的基础上,我们在业务层接口实现类中的定义一个set方法

  • service层改变
package com.my.service;
import com.my.dao.UserDao;
import com.my.dao.UserDaoImpl;
import com.my.dao.UserDaoMysqlImpl;
import com.my.dao.UserDaoOracleImpl;

public class UserServiceImpl implements UserService{
    /*
    * 关键:(要理解)
    * */
//    private UserDao userDao = new UserDaoImpl();
//    private UserDao userDao = new UserDaoMysqlImpl();
//    private UserDao userDao = new UserDaoOracleImpl();
    private UserDao userDao;

    //利用set方法进行动态的实现值的注入!
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void getUser(){
        userDao.getUser();
    }
}
  • 测试执行
import com.my.dao.UserDaoOracleImpl;
import com.my.service.UserService;
import com.my.service.UserServiceImpl;

public class MyTest {

    public static void main(String[] args) {
        //用户实际上调用的是业务层,dao层用户不需要接触
        UserService userService = new UserServiceImpl();

        //在此处体会其中的作用
        ((UserServiceImpl)userService).setUserDao(new UserDaoMysqlImpl());

        userService.getUser();
    }
}

开源用户中心 spring spring 开源协议_java_02


上述例子就是控制反转(IOC)的原型

2.4、IOC的本质
  • 是一种设计思想,而实现这种思想的方式有很多,常见的就是依赖注入(DI)
  • 控制反转其实就是获取类对象的方式发生了改变
2.5、第一个Spring程序
  • 实体类
package com.my.pojo;

public class Hello {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Hello{" +
                "name='" + name + '\'' +
                '}';
    }
}
  • Spring配置文件(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">

<!--    使用Spring来创建对象,每个对象都是bean

        类型 变量名 = new 类型();
        Hello hello = new Hello();

        id = 变量名
        class:new的对象
        property:相当于给对象中的属性设置一个值
-->
    <bean id="hello" class="com.my.pojo.Hello">
        <property name="name" value="Spring !"></property>
    </bean>

</beans>
  • 测试执行
import com.my.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    public static void main(String[] args) {

        //获取Spring的上下文对象(可以同时加载多个配置文件)
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //我们的对象都在Spring中,我们要使用直接从里面取出来就行
        Hello hello = (Hello)context.getBean("hello");
        System.out.println(hello.toString());
    }
}

总结:

  • 控制:谁来控制对象的创建?原来是程序本身,现在是Spring容器
  • 反转:原来是程序主动创建对象,现在变成被动的接收对象
  • 这就是控制反转的思想
2.6、IOC创建对象的方式
  • 通过实体类的无参构造方法创建类对象(默认的)

通过这种方式,可以验证:在配置文件被加载后,Spring容器里面的对象就已经被初始化了如图所示:

开源用户中心 spring spring 开源协议_maven_03

  • 通过实体类的有参构造方法创建类对象(又分为三种)

1、通过下标的方式

<bean id="user" class="com.my.pojo.User">
   <constructor-arg index="0" value="马老师"/>
</bean>

2、通过参数的类型(不建议使用)

<bean id="user" class="com.my.pojo.User">
    <constructor-arg type="java.lang.String" value="马老师"/>
</bean>

3、通过参数名

<bean id="user" class="com.my.pojo.User" name="user2,user3 user4">
    <constructor-arg name="name" value="马老师"/>
</bean>

参照实体类User:

package com.my.pojo;

public class User {

    private String name;

    public User(){
        System.out.println("默认的构造方法!");
    }

    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);
    }

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

总结:

  • 通过无参方式创建对象,给实体类属性赋值使用property标签
  • 通过有参方式创建对象,给实体类属性赋值统一使用constructor-arg标签
  • 注意:bean标签里面有个name属性,可以给id进行重命名,甚至可以重命名多个,之间用逗号,空格,分号分开(都行)

三、Spring配置说明

3.1、bean标签
  • id:bean的唯一标识符,也就是相当于创建的对象名
  • class:bean对象所对应的全限定名(包名+类名)
  • name:给id去别名,上面也提到了使用规范
  • property子标签:给对象中的属性设置一个值
3.2、alias标签

就是用来给id去别名,但一般以及被其name属下取代

3.3、import标签

合并配置文件

<import resource="beans.xml"/>
<import resource="beans2.xml"/>
3.4、bean的作用域

bean的有两个常用的作用域:

  • singleton单例模式:(Spring默认的)
  • prototype原型模式:每次从容器中去拿同一实体类对象的时候,就是每次去get的时候,拿到的都是新对象!(理解)

示例:

<bean id="user" class="com.my.pojo.User" p:name="马老师" p:age="22" scope="prototype"/>

四、依赖注入

4.1、通过构造器注入

参考上面的IOC创建对象方式

4.2、一般的注入方式(set方法注入)

依赖:bean“对象”的创建依赖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="address" class="com.my.pojo.Address"/>

    <bean id="student" class="com.my.pojo.Student">
        <!--普通值注入,value-->
        <property name="name" value="马老师"/>
        <!--bean(类对象)注入,ref-->
        <property name="address" ref="address"/>
        <!--数组注入,array-->
        <property name="books">
            <array>
                <value>西游记</value>
                <value>三国演义</value>
                <value>水浒传</value>
                <value>红楼梦</value>
            </array>
        </property>
        <!--list注入,list-->
        <property name="hobbys">
            <list>
                <value>打游戏</value>
                <value>听歌</value>
                <value>编程</value>
            </list>
        </property>
        <!--map注入,map-->
        <property name="score">
            <map>
                <entry key="语文" value="90"/>
                <entry key="数学" value="100"/>
            </map>
        </property>
        <!--null注入,null-->
        <property name="wife">
            <null/>
        </property>
        <!--null注入,null-->
        <property name="info">
            <props>
                <prop key="driver">xxxxx</prop>
                <prop key="url">xxxxx</prop>
            </props>
        </property>
    </bean>

</beans>
4.3、拓展注入

使用p/c命名空间

<?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命名空间注入,可以直接注入属性的值  property-->
    <bean id="user" class="com.my.pojo.User" p:name="马老师" p:age="22"/>

    <!--c命名空间注入,通过构造器来注入属性的值  constructor-args-->
    <bean id="user2" class="com.my.pojo.User" c:name="马老师" c:age="19"/>

</beans>

注意:使用这两个命名空间前,需要添加约束!

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

五、bean的自动装配

5.1、Spring中bean的装配方式

1、xml的显示配置

  • byName:根据bean的id属性来匹配类对象(id的取值需是setXx方法中的Xx,那么一个类也就一个bean)
  • byType:根据类的全限定名来匹配类对象(一个类只能在配置文件中对应一个bean)

示例:

<bean id="cat" class="com.my.pojo.Cat"/>
<bean id="dog" class="com.my.pojo.Dog"/>

<bean id="people" class="com.my.pojo.People" autowire="byName">
    <property name="name" value="马老师"/>
<!--        不在使用这种装配方式-->
<!--        <property name="cat" ref="cat"/>-->
<!--        <property name="dog" ref="dog"/>-->
</bean>

2、java代码中的显示配置(它们注解底层也是基于byName和byType的方式)

  • 使用@Autowired注解来实现,详解参考:@Autowired详解
  • 使用@Resource注解(和@Autowired注解类似)

执行顺序不同:@Autowired默认先通过byType的方式实现,@Resource默认先通过byName方式实现
注意:使用注解进行自动装配时,需要在配置文件里面导入约束开启注解支持

<?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/>
</beans>

3、隐式的自动装配(使用注解开发)

  • @Component注解相当于:<bean id="user" class="com.my.pojo.User"/>, 放在实体类的类名前面
  • @Value注解用于给实体类的属性赋值,相当于:<property name="name" value="马老师"/>, 放在属性上或者属性对应的setXx方法上都可以
  • @Component注解有几个衍生注解,我们在web开发中,会按照mvc架构进行分层

dao层:@Repository
service层:@Service
controller层:@Controller

  • @Scope注解:用来设置实体类的单例模式、原型模式等

注意:在使用注解开发时,不仅需要开启注解支持,还要指定要扫描的包,只有这样该包下的注解才会生效

<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.my"/>
<!--开启注解支持!-->
<context:annotation-config/>

六、使用java来配置Spring(先放放)

七、面向切面编程(AOP)

在学习面向切面编程之前,需要先了解什么是代理模式,以及静态代理和动态代理的工作原理和它们之间的区别。

静态代理:需要新建一个代理类(好处,不仅能实现需要完成的业务,还能够随时增添新的业务)

动态代理:调用处理程序,可以根据任意接口来动态生成对应的代理对象

静态代理:

  • 优点:随时增加新的业务,方便管理
  • 缺点:实际应用需要多个代理对象,代码量翻倍开发效率降低
    具体实现过程参考学习笔记!