Spring

2019-08-13  本文已影响0人  Roct

Spring介绍

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

Spring好处

方便解耦,简化开发:
AOP编程的支持:
声明式事务的支持:
方便程序的测试:
Spring不排斥各种优秀的开源框架
降低JavaEE API的使用难度Spring:

Spring体系结构

Spring 框架是一个分层架构,,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core ContainerData Access/IntegrationWebAOP(Aspect Oriented Programming)Instrumentation和测试部分,如下图所示:

Spring架构
Spring在项目中的架构

Spring IOC的底层实现原理

Spring IOC的底层实现原理

Spring核心jar包

Spring IOC/DI

简单的Spring框架使用

创建一个UserService接口

public void sayHello();

和它的实现类UserServiceImpl

public void sayHello {
    private String name;
    public String getName() {
          return name;
     }
    public void setName(name) {
          this.name = name;
    }
    public void sayHello() {
          System.out.println("Spring hello" + name)
    }
    
}
public void demo() {
    UserService userService = new UserServiceImpl();
    userService.setName("李四");
    userService.sayHello();
}

输出结果

Spring hello李四
// IOC
<bean id = "userService" class="com.rui.ioc.demo.UserServiceImpl>
  <property name = "name" value="李四" />
</bean>
public void demo () {
    // 创建Spring工厂, 加载classPath下的配置文件
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 通过工厂获得类
    UserService userService = (UserService) applicationContext.getBean("userService");
    userService.sayHello();
}

输出结果

Spring hello李四
使用`Spring`工厂获得类叫做`IOC`, 即将创建对象的权利交给Spring
<property name = "name" value="李四" />

叫做依赖注入, 就是在Spring创建这个对象的过程中, 将这个对象所依赖的属性注入进去

Spring的工厂类

Spring的工厂类
public void demo () {
  // 创建Spring工厂
  ApplicationContext applicationContext = new FileSystemXmlApplicationContext("c:\\applicationContext.xml");
  // 通过工厂获得类
  UserService userService = (UserService) applicationContext.getBean("userService");
  userService.sayHello();
}

Spring的Bean管理方式

Spring的Bean注解方式

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"
       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:component-scan base-package="com.rui.ioc"/>
</beans>

就会自动扫描ioc下所有的类, 在类上标注@Component/@Service/@Repository/@Controller

1、@controller 控制器(注入服务)
2、@service 服务(注入dao
3、@repository dao(实现dao访问)
4、@component (@component("xxx"))(把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="xxx" class=""/>

Spring AOP

UserDao

package com.rui.aop;

public interface UserDao {
    public void findAll();
    public void save();
    public void update();
    public void delete();
}

UserDaoImpl

package com.rui.aop;
public class UserDaoImpl implements UserDao {
    @Override
    public void findAll() {
        System.out.println("查找用户~");
    }
    @Override
    public void save() {
        System.out.println("保存用户~");
    }
    @Override
    public void update() {
        System.out.println("更新用户~");
    }
    @Override
    public void delete() {
        System.out.println("删除用户~");
    }
}

MyJdkProxy

package com.rui.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyJDKProxy implements InvocationHandler {
    private UserDao userDao;
    public MyJDKProxy(UserDao userDao) {
        this.userDao = userDao;
    }
    public Object createProxy() {
        Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao
                .getClass().getInterfaces(), this);
        return proxy;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("save".equals(method.getName())) {
            System.out.println("保存用户之前的操作");
            return method.invoke(userDao, args);
        }
        return method.invoke(userDao, args);
    }
}

aopTest

package com.rui.aop;
import org.junit.Test;
public class aopTest {
    @Test
    public void demo1() {
        UserDao userDao = new UserDaoImpl();
        userDao = (UserDao)new MyJDKProxy(userDao).createProxy();
        userDao.findAll();
        userDao.delete();
        userDao.save();
        userDao.update();
    }
}

输出结果

查找用户~
删除用户~
保存用户之前的操作
保存用户~
更新用户~

MyCglibProxy

public class MyCglibProxy implements MethodInterceptor {
    private ProductDao productDao;

    public MyCglibProxy(ProductDao productDao) {
        this.productDao = productDao;
    }
    public Object createProxy() {
        // 1. 创建核心类
        Enhancer enhancer = new Enhancer();
        // 2. 设置父类
        enhancer.setSuperclass(productDao.getClass());
        // 3. 设置回调
        enhancer.setCallback(this);
        // 4.生成代理
        Object proxy = enhancer.create();
        return proxy;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if ("save".equals(method.getName())) {
            System.out.println
                    ("============================权限校验==========================");
            return methodProxy.invokeSuper(o, objects);
        }
        return methodProxy.invokeSuper(o, objects);
    }
}

ProductDao

public class ProductDao {
    public void findAll() {
        System.out.println("查找用户~");
    }
    public void save() {
        System.out.println("保存用户~");
    }
    public void update() {
        System.out.println("更新用户~");
    }
    public void delete() {
        System.out.println("删除用户~");
    }
}

Test

@Test
public void demo1() {
     ProductDao productDao = new ProductDao();
     ProductDao proxy = (ProductDao)new MyCglibProxy(productDao).createProxy();
     proxy.findAll();
     proxy.delete();
     proxy.save();
     proxy.update();
}

输出

查找用户~
删除用户~
============================权限校验==========================
保存用户~
更新用户~

代理相关

Spring AOP增强类型

Spring AOP切面类型

自动创建代理

AspectJ AOP

1.Spring开启Aspectj

 <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"
       xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/bea      ns  http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 
   <!--    开启aspectj的注解开发-->
   <aop:aspectj-autoproxy/>
 </beans>

2.@AspectJ提供不同的通知类型

3. 在通知中通过value属性定义切点

excution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
- 匹配所有类public方法 excution(public * *(...))
- 匹配指定包下所有类方法 excution(* com.imooc.dao.*(...)) 不包含子包
- 匹配指定包下所有类方法 excution(* com.imooc.dao..*(...)) 包含子包
- 匹配指定类所有方法 excution(* com.imooc.service.UserService.*(..))
- 匹配实现特定接口所有类方法 excution(* com.imooc.service.dao.GenericDAO+.*(..))
- 匹配所有save开头的方法 excution(* save*(..))

4. @Before/@AfterReturning/@Around/AfterThrowing/After

@Aspect
public class MyAspect {
  @Pointcut(value="execution(* com.rui.aspectj.ProductDao.save(..))")
  private void save() {}

  @Pointcut(value = "execution(* com.rui.aspectj.ProductDao.update(..))")
  private void update() {}

  @Pointcut(value = "execution(* com.rui.aspectj.ProductDao.delete(..))")
  private void delete() {}

  @Before(value="save()")
  public void before(JoinPoint joinPoint) {
      System.out.println("前置通知============" + joinPoint);
  }
  @AfterReturning(value="update()",
  returning = "result")
  public void afterReturning(Object result) {
      // result为返回值
      System.out.println("后置通知============" + result);
  }
  @Around(value="delete()")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
      System.out.println("环绕前通知=====================");
      Object obj = joinPoint.proceed(); // 执行目标方法
      System.out.println("环绕后通知=====================");
      return obj;
  }
  @AfterThrowing(value="execution(* com.rui.aspectj.ProductDao.findOne(..))",
  throwing = "e")
  public void afterThrowing(Throwable e) {
      System.out.println("异常抛出通知===========" + e.getMessage());
  }
  @After(value = "execution(* com.rui.aspectj.ProductDao.findAll(..))")
  public void after() {
      System.out.println("最终通知!================");
  }
}
public class ProductDao {
  public void save() {
      System.out.println("保存商品...");
  }
  public String update() {
      System.out.println("更新商品...");
      return "hello world";
  }
  public void delete() {
      System.out.println("删除商品...");
  }
  public void findOne() {
      System.out.println("查找一个商品...");
  }
  public void findAll() {
      System.out.println("查找所有商品...");
  }
}
<!--    开启aspectj的注解开发-->
  <aop:aspectj-autoproxy/>
<!--    目标类-->
  <bean id="productDao" class="com.rui.aspectj.ProductDao" />
  <!--定义切面-->
  <bean class="com.rui.aspectj.MyAspect" />
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AspectTest {
  @Resource(name = "productDao")
  private ProductDao productDao;
  @Test
  public void demo1() {
      productDao.save();
      productDao.delete();
      productDao.findAll();
      productDao.findOne();
      productDao.update();
  }
}
前置通知============execution(void com.rui.aspectj.ProductDao.save())
保存商品...
环绕前通知=====================
删除商品...
环绕后通知=====================
查找所有商品...
最终通知!================
查找一个商品...
异常抛出通知===========/ by zero

JDBC Template

使用

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://local........." />
    <property name="username" value="root" />
    <property name="password" value="root" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="datasource" ref="datasource" />
</bean>

具体方法

// 对数据进行增删改操作
int update(String sql, Object[] args)
int update(String sql, Object... args)
public void testUpdate() {
    String sql = "insert into student(name, sex) values(?,?)";
    jdbcTemplate.update(sql, new Object[]{"zhagsan", "man"});
    // 或
    jdbcTemplate.update(sql, "zhagsan", "man");
}
// 对数据进行批量增删改操作
int [] batchUpdate(String [] sql)
int [] batchUpdate(String sql, List<Object[]> args)
public void testBatchUpdate() {
    String[] sqls = {
              "insert into student(name, sex) values ('关羽', '男')",
              "insert into student(name, sex) values ('张飞', '男')"
    };
    jdbcTemplate.batchUpdate(sqls);
}
public void testBatchUpdate() {
    String sql = insert into student(name, sex) values (?, ?)";
    List<Object []> list = new ArrayList<Object[]>();
    list.add(new Object[]{"关羽", "男"});
    list.add(new Object[]{"张飞", "男"});
    jdbcTemplate.batchUpdate(sql, list);
}

Spring事务管理

什么是事务

事务的特点

Java事务的产生

Java事务实现模式

三种事务的差异

事务接口

事务读取类型

- 脏读: 事务没提交, 提前读取
- 不可重复读: 多次读取到的数据不一致
- 幻读: 事务不是独立执行时发生的一种非预期现象

事务隔离级别

隔离级别

事务传播行为

事务传播行为

事务超时

事务回滚

Spring事务状态

编程式事务实现方式

事务管理器(PlatformTransactionManager)方式

模板事务(TransactionTemplate)的方式

声明式事务管理

声明式事务实现原理

声明式事务管理的配置类型:

声明式事务管理配置实现方式:

  <!--    引入配置文件-->
  <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <property name="order" value="2"/>
      <property name="ignoreUnresolvablePlaceholders" value="true"/>
      <property name="locations">
          <list>
              <!--配置属性文件-->
              <value>classpath:datasource.properties</value>
          </list>
      </property>
      <property name="fileEncoding" value="utf-8"/>
  </bean>

  <!--配置连接池-->
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
      <property name="driverClassName" value="${db.driverClassName}"/>
      <property name="url" value="${db.url}"/>
      <property name="username" value="${db.username}"/>
      <property name="password" value="${db.password}"/>
      <!-- 连接池启动时的初始值 -->
      <property name="initialSize" value="${db.initialSize}"/>
      <!-- 连接池的最大值 -->
      <property name="maxActive" value="${db.maxActive}"/>
      <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
      <property name="maxIdle" value="${db.maxIdle}"/>
      <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
      <property name="minIdle" value="${db.minIdle}"/>
      <!-- 最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制 -->
      <property name="maxWait" value="${db.maxWait}"/>
      <!--#给出一条简单的sql语句进行验证 -->
      <!--<property name="validationQuery" value="select getdate()" />-->
      <property name="defaultAutoCommit" value="${db.defaultAutoCommit}"/>
      <!-- 回收被遗弃的(一般是忘了释放的)数据库连接到连接池中 -->
      <!--<property name="removeAbandoned" value="true" />-->
      <!-- 数据库连接过多长时间不用将被视为被遗弃而收回连接池中 -->
      <!--<property name="removeAbandonedTimeout" value="120" />-->
      <!-- #连接的超时时间,默认为半小时。 -->
      <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}"/>

      <!--# 失效检查线程运行时间间隔,要小于MySQL默认-->
      <property name="timeBetweenEvictionRunsMillis" value="40000"/>
      <!--# 检查连接是否有效-->
      <property name="testWhileIdle" value="true"/>
      <!--# 检查连接有效性的SQL语句-->
      <property name="validationQuery" value="SELECT 1 FROM dual"/>
  </bean>
  <!-- 使用@Transactional进行声明式事务管理需要声明下面这行 -->
  <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
  <!-- 事务管理 -->
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"/>
      <property name="rollbackOnCommitFailure" value="true"/>
  </bean>
上一篇下一篇

猜你喜欢

热点阅读