Spring

1、Spring

1.1简介:

Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架

1.2组成(七大模块)

1.3Hello Spring

步骤:

1、编写实体类

public class User {
    private String name;
    private int age;
}

2、编写application.xml文件(bean容器)

<?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.hao.pojo.User">
       <property name="name" value="hello Spring"/>
        <property name="age" value="11"/>
    </bean>
</beans>

3、测试

import com.hao.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Mytest {
    public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        User user = (User)context.getBean("user");
        System.out.println(user.toString());
    }
}

小结:将对象的创建(实例化)交给ioc容器管理,由ioc容器完成对象的属性注入

一句话就是对象由Spring来创建、管理、装配!

2、DI依赖注入

依赖:bean对象的创建依赖于容器

注入:bean对象中的所有属性,由ioc容器来注入

2.1构造器注入

前提:对象类中必须有有参构造方法

package com.hao.pojo;

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "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">

    <bean id="user" class="com.hao.pojo.User">
          <!--第三种,使用下标的方式给对象属性赋值-->
     <constructor-arg index="0" value="hello Spring"/>
          <!--第二种,根据对象属性的类型来给对象属性赋值-->
     <constructor-arg type="java.lang.String" value="豪神"/>
          <!--第一种,使用对象属性的名字给对象属性赋值-->
        <constructor-arg name="name" value="123"/>
    </bean>
</beans>

2.2set方法注入

前提:必须有无参构造方法,使用无参构造注入

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

    <bean id="user" class="com.hao.pojo.User">
       <property name="name" value="hello Spring"/>
        <property name="age" value="11"/>
    </bean>
</beans>

2.3基于注解的注入

2.4c命名和p命名空间注入(扩展)

注意:需要导入c命名和p命名的头文件的约束

其实就是构造器注入和set注入方式一样,一个根据构造器注入属性值,一个直接set进去属性值。

3、Bean的作用域

  • singleton:单例模式,在整个Spring IoC容器中,使用singleton 定义的 bean 只有一个实例(默认使用单例模式)
<bean id="user" class="com.hao.pojo.User" scope="singleton">
       <property name="name" value="hello Spring"/>
        <property name="age" value="11"/>
    </bean>
public class Mytest {
    public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        User user = context.getBean("user",User.class);
        User user2 = context.getBean("user",User.class);
        System.out.println(user==user2);
    }
}
//结果为true
  • prototype:原型模式,每次通过容器的getBean方法获取 prototype 定义的 bean 时,都产生一个新的 bean 实例
 <bean id="user" class="com.hao.pojo.User" scope="prototype">
       <property name="name" value="hello Spring"/>
        <property name="age" value="11"/>
    </bean>
public class Mytest {
    public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        User user = context.getBean("user",User.class);
        User user2 = context.getBean("user",User.class);
        System.out.println(user==user2);
    }
}
//结果为false
  • 只有在 Web 应用中使用Spring时,request、session、global-session 作用域才有效
    • request:对于每次 HTTP 请求,使用 request 定义的 bean 都将产生一个新实例,即每次 HTTP 请求将会产生不同的 bean 实例。
    • session:同一个 Session 共享一个 bean 实例。
    • global-session:同 session 作用域不同的是,所有的Session共享一个Bean实例。

4、Bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式。
  • Spring会在上下文中自动寻找,并自动给bean装配属性。

自动装配的方式:

  • byName:根据bean的名字进行装配,当一个bean的名称和其他bean的属性名一致,则自动装配。
<?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="cat" class="com.hao.pojo.Cat"/>
    <bean id="dog" class="com.hao.pojo.Dog"/>
    <bean id="people" class="com.hao.pojo.People" autowire="byName">
        <property name="name" value="锦豪"/>
    </bean>
</beans>
  • byType:根据bean的类型进行装配,当一个bean的属性类型与其他bean的数据类型一致,则自动装配。
<?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="cat" class="com.hao.pojo.Cat"/>
    <bean id="dog" class="com.hao.pojo.Dog"/>
    <bean id="people" class="com.hao.pojo.People" autowire="byType">
        <property name="name" value="锦豪"/>
    </bean>
</beans>

还可以使用@Autowite、@Resource注解来实现自动装配

注意:使用注解需要在xml文件中导入context的注解支持

 <context:annotation-config/>

小结:

  • byName的时候,需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致。
  • byType的时候,需要保证所有的class的唯一,并且这个bean需要和自动注入的属性的类型一致。

5、使用注解开发

  • @Component:组件,放在类上,说明这个类被Spring的IOC容器托管了,就是相当于一个bean。

  • @Scope:bean的作用域

  • @Value:给bean中的属性赋值。

  • 衍生的注解:

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

6、AOP

6.1 什么是AOP?

​ 切面编程,就是在你项目原有的功能基础上,通过AOP去添加新的功能,这些功能是建立在原有功能的基础上的,而且原有的功能并不知道你已经添加了新的功能。比如说,你去ATM取钱,取钱是一个功能,取完钱后向你的手机发送一条取钱信息,这就是新加的功能。
​ AOP就是在某一个类或方法执行前后打个标记,声明在执行到这里之前要先执行什么,执行完这里之后要接着执行什么。插入了新的执行方法。

img

​ 当我们需要在许多类中添加相同逻辑(或记录等其他)代码的时候,一般我们编程会在每一个类中都写上这些代码。当需要修改的时候,我们又必须找出这些类来删除这些逻辑代码。这里,你觉不觉得有什么问题。这好像关系到复用的问题,那么可以用聚合或继承来完成?那么再继续下去,我们需要这些逻辑代码指定到类中的某个方法前面执行,或者在方法后面执行,又或者我想指定在类的某一个位置去执行它,那么这就不是复用的问题了,而是要修改类了,变成动态的了。那么就出现了aop这个概念-面向切面编程。

​ 如上图,黑线为一个流程代码,红线为切入的代码。即在5个流程中固定位置插入了3个逻辑代码,如果你不需要的时候,你完全可以撤出红线代码,而要修改的话,也只需修改这三个类(红线)即可,因为主代码(黑线)和添加代码(红线)是没有耦合的,相当于插拔式的。而且spring aop支持声明式的配置,使得aop更加方便。

6.2使用Spring实现Aop

注意:在使用Aop之前,需要导入aop的依赖包,还需要再xml配置文件中导入aop的约束

<dependencies>
      <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.9.4</version>
      </dependency>
  </dependencies>
<?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"
       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">
</beans>

方式一:使用Spring的API接口来实现AOP【主要是SpringApi接口的实现】

实现Springaop的接口,生成执行环绕前后的类

package com.hao.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeLog implements MethodBeforeAdvice {
    //method: 要执行的目标对象的方法
    // args: 参数
    //target: 目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"执行了"+method.getName()+"方法");
    }
}
package com.hao.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class  AfterLog implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"的方法,返回结果为"+returnValue);
    }
}

编写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"
       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">

    <bean id="userService" class="com.hao.service.UserServiceImpl"/>
    <bean id="before" class="com.hao.log.BeforeLog"/>
    <bean id="after" class="com.hao.log.AfterLog"/>
 
   <!-- aop的第一种方式-->
   <aop:config>
         <aop:pointcut id="pointCut" expression="execution(*     com.hao.service.UserServiceImpl.*(..))"/>
         <aop:advisor advice-ref="before" pointcut-ref="pointCut"/>
         <aop:advisor advice-ref="after" pointcut-ref="pointCut"/>
     </aop:config>
</beans>

方式二:自定义来实现AOP【主要是切面定义】

自定义一个切面

package com.hao.diy;

public class DiyPointCut {
    public void before(){
        System.out.println("==========方法执行前==========");
    }
    public void after(){
        System.out.println("==========方法执行后==========");
    }
}

编写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"
       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">

    <bean id="userService" class="com.hao.service.UserServiceImpl"/>
<!--第二种方法-->
    <bean id="diy" class="com.hao.diy.DiyPointCut"/>
    <aop:config>
        <aop:aspect ref="diy">
            <aop:pointcut id="point" expression="execution(* com.hao.service.UserServiceImpl.*(..))"/>
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
</beans>

方式三:使用注解实现aop

其实就是将方式二使用注解的方式实现

定义一个切面类

package com.hao.diy;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect  //标注这个类为一个切面
public class AnnotationPointCut {
    @Before("execution(* com.hao.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("==========方法执行前===========");
    }
}

注意:在使用注解实现aop时,需要在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
        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/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="userService" class="com.hao.service.UserServiceImpl"/>
    <!--第三种aop实现方式-->
    <context:component-scan base-package="com.hao"/>
    <context:annotation-config/>
    <aop:aspectj-autoproxy/>
</beans>

7、Spring整合Mybatis

步骤:导入jar包

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.5</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.2</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.8</version>
    </dependency>
</dependencies>

2、编写mybatis-config.xml,Spring-dao.xml,和application.xml配置文件进行整合

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="com.hao.pojo"/>
    </typeAliases>

</configuration>
<?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="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=false"/>
      <property name="username" value="root"/>
      <property name="password" value="1234"/>
  </bean>

   <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
       <property name="dataSource" ref="dataSource"/>
       <!--绑定Mybatis配置文件和映射mapper.xml文件-->
       <property name="configLocation" value="classpath:mybatis-config.xml"/>
       <property name="mapperLocations" value="classpath:com/hao/mapper/*.xml"/>
   </bean>
    <!--就是我们平常使用的SqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--<constructor-arg index="0" ref="sqlSessionFactory"/>-->
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>
<?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">

 <import resource="spring-dao.xml"/>
    <bean id="userMapper2" class="com.hao.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

    <bean id="userMapper" class="com.hao.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>

3、编写实体类、接口、接口的实现类、mapper.xml文件

package com.hao.pojo;

import lombok.Data;

@Data
public class User {
    private int id;
    private String myname;
    private int age;
    private String address;
}
package com.hao.mapper;

import com.hao.pojo.User;

import java.util.List;

public interface UserMapper {
    public List<User> queryUser();
}

package com.hao.mapper;

import com.hao.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl implements UserMapper {
    private SqlSessionTemplate sqlSession;

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

    public List<User> queryUser() {
        return sqlSession.getMapper(UserMapper.class).queryUser();
    }
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hao.mapper.UserMapper">
    <select id="queryUser" resultType="com.hao.pojo.User">
    select * from users
  </select>
</mapper>

4、测试

import com.hao.mapper.UserMapper;
import com.hao.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Mytest {
    public static void main(String[] args) throws IOException {
      ApplicationContext context = new ClassPathXmlApplicationContext("applicaionContext.xml");
        UserMapper mapper = context.getBean("userMapper", UserMapper.class);
        for (User user : mapper.queryUser()) {
            System.out.println(user);
        }
    }
}

8、Spring事务

  • 声明式事务:AOP

再配置文件spring-dao.xml中配置事务,并横切进去

<bean id="transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--结合AOP实现事务的织入-->
    <tx:advice id="TxAdvice" transaction-manager="transaction">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.hao.mapper.*.*(..))"/>
        <aop:advisor advice-ref="TxAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
  • 编程式事务:需要在代码中,进行事务的管理

为什么要使用事务?

  • 如果不配置事务,可能存在数据提交不一致的情况
  • 如果我们不在Spring中去配置事务,就需要在代码中手动配置事务
  • 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎。
posted @ 2020-10-30 22:22  小胖学java  阅读(140)  评论(0编辑  收藏  举报