spring

spring

介绍

Spring框架是一个开放源的应用程序框架,由[Rod Johnson](https://baike.baidu.com/item/Rod Johnson/1423612?fromModule=lemma_inlink)发起,是针对bean的生命周期进行管理的轻量级容器

  • AOP(面向切面)
  • IOC(控制反转)
  • 容器

组成

img

扩展

  • Spring Boot
    • 快速开发的脚手架
    • 基于Spring Boot可以快速开发单个微服务
    • 约定大于配置
  • Spring Cloud
    • Spring Cloud 是基于Spring Boot实现的

学习Spring Boot的前提是Spring 和Spring MVC


IOC

public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoImpl();

    @Override
    public void getUser() {
        userDao.getUser();
    }
}

之前通过这种方式,程序是死的只要需要给变new UserDaoImpl();这里就要改

public class UserServiceImpl implements UserService {
    private UserDao userDao;

    //利用set动态注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUser() {
        userDao.getUser();
    }
}
UserServiceImpl userService = new UserServiceImpl();
        //userService.setUserDao(new UserDaoImpl());
        userService.setUserDao(new UserDaoOracleImpl());
        //userService.setUserDao(new UserDaoMysqlImpl());
        userService.getUser();

但是这里只加了一个set方法就可以动态的根据业务动态实现dao层

image-20241206191233292

配置模版

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

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions go here -->

</beans>
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

创建对象

无参(默认)

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Hello hello = (Hello) context.getBean("Hello");
        System.out.println(hello.toString());
package com.dong.pojo;

public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

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

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

<bean id="Hello" class="com.dong.pojo.Hello">
        <property name="str" value="Hello Spring"/>
    </bean>

通过容器去自动创建框架,而不是传统的new Hello();

有参

public class User {
    private int id;
    private String name;
    private int age;
}
  • 通过索引创建
<!--1.通过索引创建    -->
    <bean id="User" class="com.dong.pojo.User">
        <constructor-arg index="0" value="1"/>
        <constructor-arg index="1" value="小王"/>
        <constructor-arg index="2" value="18"/>
    </bean>
  • 通过类型创建
<bean id="User" class="com.dong.pojo.User">
        <constructor-arg type="int" value="2"/>
        <constructor-arg type="java.lang.String" value="小李"/>
        <constructor-arg type="int" value="22"/>
    </bean>
  • 通过参数名创建
<bean id="User" class="com.dong.pojo.User">
        <constructor-arg name="id" value="3"/>
        <constructor-arg name="name" value="小张"/>
        <constructor-arg name="age" value="33"/>
    </bean>

Spring配置

  • alias(起别名)

<alias name="User" alias="jflasjlfjsjflas"/>

  • import(导入别的配置文件)
<?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="beans.xml"/>

</beans>

Bean依赖注入

构造器注入

<bean id="User" class="com.dong.pojo.User">
        <constructor-arg name="id" value="3"/>
        <constructor-arg name="name" value="小张"/>
        <constructor-arg name="age" value="33"/>
    </bean>

SET注入

为不同的属性注入值

public class Example {
    private int age;
    private String name;
    private User user;
    private List<String> list;
    private Map<String, String> map;
    private Set<String> set;
    private Properties info;
    
    //get set
    
}
<!-- name="example"起别名   -->
    <bean id="Example" class="com.dong.pojo.Example" name="example">
        <!--普通注入 -->
        <property name="age" value="10"/>
        <property name="name" value="小王"/>

        <!--Bean注入-->
        <property name="user" ref="User"/>

        <!--数组注入 -->
        <property name="arr" >
            <array>
                <value>中国</value>
                <value>美国</value>
                <value>英国</value>
            </array>
        </property>

        <!--list注入-->
        <property name="list">
            <list>
                <value>唱</value>
                <value>跳</value>
                <value>练球</value>
            </list>
        </property>

        <!--map注入-->
        <property name="map">
            <map>
                <entry key="键1" value="值1"/>
                <entry key="键2" value="值2"/>
                <entry key="键3" value="值3"/>
            </map>
        </property>

        <!--set注入-->
        <property name="set">
            <set>
                <value>LOL</value>
                <value>COC</value>
                <value>BOB</value>
            </set>
        </property>

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

        <!-- Properties       -->
        <property name="info">
            <props>
                <prop key="学号">2023013508</prop>
                <prop key="性别">男</prop>
            </props>
        </property>

    </bean>

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

扩展方式注入

  • p命名空间
<!--p名名空间注入    -->
    <bean id="StudentP" class="com.dong.pojo.Student" p:id="18" p:name="学生p"/>
  • c命名空间 xmlns:c="http://www.springframework.org/schema/c"
<bean id="person"  c:name="Tom" c:age="20"/>

Bean的作用域

作用域 描述
singleton 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
global-session 一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境
<bean id="Student2" class="com.dong.pojo.Student"   scope="prototype">

request session global-session在web中才能用


Bean的自动装配

  • Spring会在上下文中自动寻找,并自动装配Bean的属性

  • 在xml中显示的配置

  • 在java中显示的配置

  • 隐式的自动装配Bean

ByName

<!--ByName
      根据配置文件的上下文寻找id为类的set方法里的参数名寻找
      public void setDog(Dog dog) {
        this.dog = dog;
    }
    参数名:dog
      -->
    <bean id="dog" class="com.dong.pojo.Dog"/>
    <bean id="cat" class="com.dong.pojo.Cat"/>

    <bean id="People" class="com.dong.pojo.People" autowire="byName">
        <property name="name" value="小王"/>
    </bean>

ByType

<!--ByType
      根据配置文件的上下文寻找id为类的set方法里的类型名寻找
	public void setDog(Dog dog) {
        this.dog = dog;
    }
	参数类型:Dog
      -->
    <bean id="Dog" class="com.dong.pojo.Dog"/>
    <bean id="Cat" class="com.dong.pojo.Cat"/>

    <bean id="People" class="com.dong.pojo.People" autowire="byType">
        <property name="name" value="小王"/>
    </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"
       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/>

</beans>

注解支持: context:annotation-config/

public class People {
    private String name;
    @Autowired
    private Dog dog;
    @Autowired
    private Cat cat;
}

使用注解开发

使用注解需要支持

<!--扫描该包下的注解    -->
    <context:component-scan base-package="com.dong.pojo"/>
    <!--开启注解支持    -->
    <context:annotation-config/>
  • bean
//@Component 等价于<bean id="user" class="com.dong.pojo.User"/>
@Component
public class User {
    @Value("小王")
    private String name;
}

  • 属性注入
@Component
public class User {
    @Value("小王")
    private String name;
}
  • 与@Component的同类
@Component 组件
@Service dao层
@Controller controller层
@Service service层
    
//这四个注解的功能都是一样的,都是将这个类装配到Spring容器中,只是为了区分层
  • 自动装配
@Autowired
  • 作用域
@Scope("singleton")  //singleton单例 prototype ....

xml和注解相比:

xml万能

注解不是自己的类使用不了,维护麻烦


使用java配置Spring

配置类

@Configuration
@Import(SpringConfig2.class) //引用其他的配置类
public class SpringConfig {

    //返回值为配置文件的class:
    //方法名为配置文件的id
    //等价与<bean id="getUser" class="com.dong.pojo.User"/>
    @Bean
    public User getUser(){
        return new User();
    }
}

测试

通过AnnotationConfigApplicationContext引入配置类

public void test2() {
        ApplicationContext context = new      AnnotationConfigApplicationContext(SpringConfig.class);
        User bean = (User) context.getBean("getUser");
        System.out.println(bean.getName());

    }

代理模式

  • 静态代理
  • 动态代理

静态代理

1.接口

public interface Rent {
    void rent();
}

2.真实角色

//房东
public class RooMHost implements Rent{
    @Override
    public void rent() {
        System.out.println("房东卖房子");
    }
}

3.代理

public class Proxy implements Rent{
    public RooMHost host;

    public Proxy(RooMHost host) {
        this.host = host;
    }

    @Override
    public void rent() {
        host.rent();
    }
}

4.客户端访问

public class Client {
    public static void main(String[] args) {
        //静态代理
        RooMHost host = new RooMHost();
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

一个真实角色就会产生一个代理,多个真实角色的话开发难

AOP

面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术

execution表达式

execution(* com.sample.service.impl..*.*(..))

解释如下:

符号 含义
execution() 表达式的主体;
第一个” * “符号 **表示返回值的类型任意; **
com.sample.service.impl AOP所切的服务的包名,即,我们的业务部分
包名后面的” .. “ 表示当前包及子包
第二个” * “ 表示类名,*即所有类。此处可以自定义,下文有举例
.*(..) 表示任何方法名,括号表示参数,两个点表示任何参数类型

接口

public interface UserService {
    void add();
    void update();
    void delete();
    void select ();
}

实现类

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加用户");
    }

    @Override
    public void update() {
        System.out.println("更新用户");
    }

    @Override
    public void delete() {
        System.out.println("删除用户");
    }

    @Override
    public void select() {
        System.out.println("查询用户");
    }
}

1. 原生Spring API接口 + xml配置 切入

方法执行前

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

方法执行后

public class UserServiceAfterLog implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行后:    " + target.getClass().getName() + "被执行了, " + "返回结果:" + returnValue);
    }
}

配置文件

<?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    -->
<bean id="UserServiceImpl" class="com.dong.service.UserServiceImpl"/>
    <bean id="UserServiceBeforeLog" class="com.dong.log.UserServiceBeforeLog"/>
    <bean id="UserServiceAfterLog" class="com.dong.log.UserServiceAfterLog"/>

    <!--配置AOP-->
    <aop:config>
        <!-- 切入点-->
        <aop:pointcut id="pointcut" expression="execution(* com.dong.service.UserServiceImpl.*(..))"/>

        <!-- 执行环绕增加-->
        <aop:advisor advice-ref="UserServiceBeforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="UserServiceAfterLog" pointcut-ref="pointcut"/>
    </aop:config>



</beans>

测试

@Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理的是接口,而不是实现类
        UserService userService = (UserService) context.getBean("UserServiceImpl");
        userService.add();
    }

2. 自定义(自定义切面)

自定义切面

//自动义切面
public class DiyPointCut {
    public void before() {
        System.out.println("===========================before===========================");
    }

    public void after() {
        System.out.println("===========================after===========================");
    }
}

xml配置

    <!--2.自定义类-->
    <bean id="DiyPointCut" class="com.dong.diy.DiyPointCut"/>

    <aop:config>
        <!--自定义切面 ref:要引用的类-->
        <aop:aspect ref="DiyPointCut">
            <!--切入点-->
            <aop:pointcut id="point" expression="execution(* com.dong.service.UserServiceImpl.*(..))"/>

            <!--通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

3. 注解实现AOP

定义切面

//@Aspect 声明这个类是一个切面
@Aspect
public class AnnoPointCut {
    @Before("execution(* com.dong.service.UserServiceImpl.*(..))")
    public void before() {
        System.out.println("===========================注解before===========================");
    }

    @After("execution(* com.dong.service.UserServiceImpl.*(..))")
    public void after() {
        System.out.println("===========================注解after===========================");
    }
}

配置

<!--3.注解实现AOP-->
    <bean id="AnnoPointCut" class="com.dong.annotation.AnnoPointCut"/>
    <!--开启注解支持 -->
    <aop:aspectj-autoproxy/>

整合Mybatis

依赖

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

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

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>



        <!-- MyBatis Core -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>

        <!-- MyBatis Spring Integration -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.1.2</version>
        </dependency>


        <!-- MySQL JDBC Driver -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

    </dependencies>

[ applicationContext.xml](....\java\JavaWeb\StudySpring\Spring-08-Mybatis\src\main\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 id="dataScore" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/testdatabase?useUnicode=true&amp;characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!--获取sqlSessionFactory代替Mybatis的Util类-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataScore"/>

        <!--获取Mybatis的配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--获取Mapper的配置文件(注册mapper)-->
        <property name="mapperLocations" value="classpath:com/dong/mapper/UserMapper.xml"/>
    </bean>

    <!--SqlSessionTemplate就是我们使用得sqlSession   -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

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


</beans>

UserMapperImpl

public class UserMapperImpl implements UserMapper {
    private SqlSessionTemplate sqlSession;

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

    @Override
    public User getUserById(int id) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUserById(id);
    }
}

测试

public class MyTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserMapper userMapperImpl = context.getBean("userMapper",UserMapper.class);
        userMapperImpl.getUserById(1);
    }

}


优化配置

通过导入配置

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

    <import resource="spring-dao.xml"/>
        <!--后续导入spring-mvc.xml    -->
    <import resource="spring-mvc.xml"/>

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

    <bean id="userMapper2" class="com.dong.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

</beans>

方式一

public class UserMapperImpl implements UserMapper {
    private SqlSessionTemplate sqlSession;

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

    @Override
    public User getUserById(int id) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUserById(id);
    }
}
    <bean id="userMapper" class="com.dong.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>

2.方式二(继承SqlSessionDaoSupport)

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
    @Override
    public User getUserById(int id) {
//        SqlSession sqlSession = getSqlSession();
//        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//        return mapper.getUserById(id);

        return getSqlSession().getMapper(UserMapper.class).getUserById(id);
    }
}
    <bean id="userMapper2" class="com.dong.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

Spring声明事务

声明式事物:aop

编程式事物

通过AOP把事物织入进去

    <!--配置声明事务    -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg name="dataSource" ref="dataSource" />
    </bean>

    <!-- 结合AOP实现事务的织入   -->
    <!-- 配置事务的通知   -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--给哪些方法配置事务        -->
        <tx:attributes>
            <tx:method name="addUser" propagation="REQUIRED"/>
            <tx:method name="updateUser" propagation="REQUIRED"/>
            <tx:method name="deleteUser" propagation="REQUIRED"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事务切入    -->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.dong.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>

Propagation类的事务属性详解:

REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

MANDATORY:支持当前事务,如果当前没有事务,就抛出异常

REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

posted @ 2025-03-24 21:13  -殇情-  阅读(17)  评论(0)    收藏  举报