一、Spring简介

 

Spring是由Rod Jahnson在2004年推出的框架,

早在2002年就有了Spring的前身interface21,也是由Rod Jahson发表的。

Spring的初衷就是使JAVA EE开发应该更加简单,它在一定程度上可以看作为一个容器。

官网:https://spring.io

 

Spring的优点:

  1. 简化了java企业级应用的开发
  2. Spring是免费开源的框架
  3. Spring是轻量级的,非入侵式的框架
  4. 控制反转(IOC),面向切面(AOP)特性
  5. 容易整合其他的框架,支持事务等

 

Spring核心模块:

Spring为开发者提供了七大核心模块

spring是哪国开发的框架 spring框架属于哪家公司_User

1、核心容器(Core)

Spring框架中最基础的部分,它通过依赖注入(DI)来实现容器对Bean的管理。BeanFactory是工厂模式的一个实现,它使用IoC将应用配置和依赖说明从实际的应用代码中分离出来,也是是任何Spring应用的核心。

2、应用上下文(Context)

核心模块的BeanFactory使Spring成为一个容器,而上下文模块使它成为一个框架。这个模块扩展了BeanFactory的概念,增加了对国际化(I18N)消息、事件传播以及验证的支持。

3、Spring的AOP模块

Spring在它的AOP模块中提供了对面向切面编程的丰富支持。这个模块是在Spring应用中实现切面编程的基础。Spring的AOP模块也将元数据编程引入了Spring。可以通过AOP面向切面编程,在不改变原来代码的情况下对旧方法和功能的增强。

4、JDBC抽象和DAO模块

Spring的JDBC和DAO模块抽取了原生JDBC重复的代码,可以保持你的数据库访问代码干净简洁,并且可以防止因关闭数据库资源失败而引起的问题。这个模块给出的错误消息上面建立了一个有意义的异常层。这个模块还使用了Spring的AOP模块为Spring应用中的对象提供了事务管理服务。

5、对象/关系映射集成模块

Spring提供了ORM模块。Spring为几ORM框架提供了集成方案,包括Hibernate、JDO和iBATIS SQL映射。Spring的事务管理支持这些ORM框架中的每一个也包括JDBC。

6、Spring的Web模块

Web上下文模块建立于应用上下文模块之上,提供了一个适合于Web应用的上下文。另外,这个模块还提供了一些面向服务支持。也提供了Spring和其它Web框架的集成,比如Struts等。

7、Spring的Mvc框架

Spring为构建Web应用提供了一个功能全面的MVC框架。虽然Spring可以很容易地与其它MVC框架集成,例如Struts,但Spring的MVC框架使用IoC对控制逻辑和业务对象提供了完全的分离。

 

二、控制反转(IOC)

控制反转是一种通过描述(XML或注解)通过第三方去产生或获取对象的方式。
以前编程,由程序员自己声明对象,有了IOC,可以将对象托管到第三方容器中,从容器中获取依赖。
在Spring中实现控制反转的是IOC容器。其实现方法是依赖注入(DI)。

创建步骤:

1、maven中导入依赖

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>

        <!--junit包-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

2、创建实体类

public class User {
    private String name;


    public void show(){
        System.out.println("IOC Study");
    }
}

3、创建spring的配置文件bean1.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="hello" class="com.llj.pojo.User"/>

</beans>

4、单元测试

@Test
    public void test(){
    	//解析beans.xml配置文件,生成管理Bean对象的容器context
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        User user = (User) context.getBean("hello");
        user.show();
    }

Spring先从xml文件或者注解配置类中获取注入的对象和参数,然后程序员再从容器中获取对应的值。

 

XML配置方法

1、无参构造:

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

2、有参构造:

<!--根据构造器参数下标-->
<bean id="user1" class="com.llj.pojo.User">
        <constructor-arg index="0" value="张三"/>
</bean>

<!--根据构造器类型-->
<bean id="user2" class="com.llj.pojo.User">
       <constructor-arg type="java.lang.String" value="李四"/>
</bean>
<!--根据构造器参数名称-->
<bean id="user3" class="com.llj.pojo.User">
        <constructor-arg name="name" value="张三"/>
</bean>

3、set方法

<!-- 2、 通过set方法注入属性  -->
    <bean id="book1" class="com.llj.User">
        <!-- 使用property完成属性的注入
            name:类里面属性名称
            value:向属性赋值
        -->
        <property name="name" value="曹贼"></property>
    </bean>

4、通过p标签进行注入 

在beans标签中添加: xmlns:p="http://www.springframework.org/schema/p"

<!--     4、 通过p空间set注入属性  -->
     <bean id="book1" class="com.llj.User" p:name="刘皇叔">
</bean>

三、依赖注入:

1、内部bean  手动装配

<bean id="empt" class="com.llj.dept.Empt">
        <property name="ename" value="张三"></property>
        <property name="gender" value="男"></property>
        <property name="dept">
            <bean id="dept" class="com.llj.dept.Dept">
                <property name="dname" value="安保部"></property>
            </bean>
        </property>
    </bean>

2、级联bean

<bean id="empt" class="com.llj.dept.Empt">
        <property name="ename" value="huahua"></property>
        <property name="gender" value="女"></property>
        <property name="dept" ref="dept"></property>
    </bean>
    <bean id="dept" class="com.llj.dept.Dept">
        <property name="dname" value="技术部"></property>
    </bean>

3、各种数据结构进行属性注入(String,list,map,set)

<bean id="stu" class="com.llj1.stu">
         <!--String注入-->
        <property name="strings">
            <array>
                <value>星期1</value>
                <value>星期2</value>
                <value>星期3</value>
            </array>
        </property>
         <!--list注入-->
        <property name="lists">
            <list>
                <value>一月</value>
                <value>二月</value>
                <value>三月</value>
                <value>四月</value>
            </list>
        </property>

         <!--map注入-->
        <property name="maps">
            <map>
                <entry key="小猫" value="喵喵"></entry>
                <entry key="小狗" value="汪汪"></entry>
                <entry key="小猪" value="哼哼"></entry>
            </map>
        </property>

         <!--set注入-->
        <property name="sets">
            <set>
                <value>加顿男爵</value>
                <value>黑色玫瑰</value>
            </set>
        </property>

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

 

四、 autowire 自动装配:

<bean id="emp" class="com.autowire.Emp" autowire="byName"></bean>

    <bean id="dept" class="com.autowire.Dept"></bean>

autowire=“byName” 流程
1.会先找User类的所有set方法
2.set方法名去掉set,首字母小写就是自动装配名字
3.去配置文件中的bean中找有没有相同的名字
4.有就自动装配,没有可能会报错

 

autowire=“byType” 是根据类型进行装配的,类型必须唯一,不唯一会报NoUniqueBeanDefinitionException错

 

用注解自动装配:

第一步:在XML导入context约束

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

</beans>

第二步:导入注解配置

<context:annotation-config/>

第三步:在实体类中加入注解

public class User {
    @Autowired(required = false)
    @Qualifier(value = "cat2")
    private Cat cat;
    @Autowired
    private Dog dog;
    private String str;

    public Cat getCat() {
        return cat;
    }

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

    public Dog getDog() {
        return dog;
    }

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

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

@Autowired注解

@Autowired 注释是一个用于容器 ( container ) 配置的注释。

按类型进行匹配,required=false表示可以为空 ,

相似作用的注解有 :@Required   @Primary  @Qualifier ,但是@Qualifier不能单独使用,需要前面加上@Autwired

 

五、注解开发

步骤:

①在xml文件中添加context空间

<?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
       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/>
    <!--扫描com.llj包下的注解-->
    <context:component-scan base-package="com.llj"/>

</beans>

②创建实体类配置注解

@Component("user")
@Scope("singleton")
//相当于<bean id="user" class=""/>
public class User {
    @Value("1")
    private int id;
    @Value("张三")
    //<property name="name" value="张三"/>
    private String name;

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

③测试

public class MyTest {

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User bean = (User) context.getBean("user");
        System.out.println(bean);
    }
}

@Component注解

表示配置一个bean

三层架构的三个衍生注解:

Dao层:@Reposity

Service层 : @Service

Controller层  : @Controller

@Autowire注解

自动装配属性,搭配@Qualifier可以根据名字进行自动装配

@Nullable 可以为空

@Scope注解(作用域)

  • singleton:单例模式
  • prototype:多例模式

 

注解配置

注解配置可代替xml配置文件,但是一般可以两者一起用。

注解配置可以方便注入我们自己写的类,xml文件可以导入其他资源,两者各有优势

新建Config包,包下建注解类

@Configuration  //代表这是一个配置类
@Import(MyConfig2.class)  //用于合并其他配置类
public class MyConfig {

   @Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
   public Dog dog(){
       return new Dog();
  }

}

AOP面向切面

 

理解:AOP(Aspect Oriented Programming)面向切面编程,通过预编译和运行期动态代理实现程序功能的统一维护的种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分的耦合度降低,提高程序的可重用性,提高了开发效率。

AOP中的名词

横切关注点:跨越应用程序多个模块的方法或功能。如日志 , 安全 , 缓存 , 事务等等 …
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
目标(Target):被通知对象。
代理(Proxy):向目标对象应用通知之后创建的对象。
切入点(PointCut):切面通知 执行的 “地点”的定义。
连接点(JointPoint):与切入点匹配的执行点。

使用AOP步骤

1、导入maven中的相关包

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

2、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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.Anno"></context:component-scan>

    <!--开启aspectj-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

3、创建代理类和被代理类

被代理类

@Component
public class pojo {
    public void eat(){
        System.out.println("吃饭");
    }

}

 代理类

@Component
@Aspect
@Order(1)
public class pojoProxy {
    @Before(value = "execution(* rewiew.pojo.eat(..))")
    public void pBefore(){
        System.out.println("洗手");
    }

}

4、测试

@Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
        pojo pojo1 = (pojo) context.getBean("pojo");
        pojo1.eat();
    }

 注解配置AOP的几个通知方式

@Before前置通知,在连接点方法前调用

@Around环绕通知,它将覆盖原有方法,但是允许你通过反射调用原有方法,后面会讲

@After后置通知,在连接点方法后调用

@AfterReturning返回通知,在连接点方法执行并正常返回后调用,要求连接点方法在执行过程中没有发生异常

@AfterThrowing异常通知,当连接点方法异常时调用

 

Spring整合MyBatis

第一步:导入核心包

<!--单元测试-->
<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
</dependency>
<!--mybatis-->
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.5.2</version>
</dependency>
<!--数据库连接-->
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.47</version>
</dependency>
<!--spring相关的-->
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>5.1.10.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>5.1.10.RELEASE</version>
</dependency>
<!--aop织入-->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.9.4</version>
</dependency>
<!--mybatis-spring整合包 【重点】-->
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
   <version>2.0.2</version>
</dependency>

第二步配置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="dataSource"   class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
    </bean>

<!--配置sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--关联Mybatis-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/kuang/dao/*.xml"/>
    </bean>

<!--注册sqlSessionTemplate , 关联sqlSessionFactory-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
       <!--利用构造器注入-->
       <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

</beans>

第三步:配置dao --> Mapper

public class UserDaoImpl implements UserMapper {

   //sqlSession不用我们自己创建了,Spring来管理
    @Autowird
   private SqlSessionTemplate sqlSession;

   public void setSqlSession(SqlSessionTemplate sqlSession) {
       this.sqlSession = sqlSession;
  }

   public List<User> selectUser() {
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       return mapper.selectUser();
  }
   
}

 

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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

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

    <bean id="userMapper" class="com.yang.mapper.UserMapperImpl2">
        <property name="sqlSessionTemplate" ref="sqlSession"/>
    </bean>
    <!--配置声明事务注入-->
    <!--要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager 对象:-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
        <!--或者使用构造注入-->
        <!--<constructor-arg ref="dataSource" />-->
    </bean>

    <!--结合AOP实现事务的织入-->
    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--给哪些方法配置事务-->
        
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="select" read-only="true"/>
            <!--全部方法-->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事务切入-->
    <aop:config>
    	<!--该包下的所有方法-->
        <aop:pointcut id="txPointCut" expression="execution(* com.yang.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
</beans>

 

配置事务的传播特性 propagation
                PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
                PROPAGATION_SUPPORTS:支持当前事务,如果没有当前事务,就以非事务方法执行。
                PROPAGATION_MANDATORY:使用当前事务,如果没有当前事务,就抛出异常。
                PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
                PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
                PROPAGATION_NEVER:以非事务方式执行操作,如果当前事务存在则抛出异常。
                PROPAGATION_NESTED:    如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED 类似的操作