Spring5框架学习笔记(二)

Spring5框架学习笔记(二)


AOP(概念)
  1. 什么是AOP?
    1. 面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑的各个部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率。
    2. 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能。
AOP(底层原理)
  1. AOP底层使用动态代理
    有两种情况的动态代理:
    1. 第一种 有接口使用JDK动态代理,创建接口实现类代理对象,增强类的方法
    2. 第二种 无接口使用CGLIB动态代理,创建子类的代理对象,增强类的方法
  2. AOP(JDK动态代理)
    1. 使用JDK动态代理,使用Proxy类里面的方法创建代理对象,调用newProxyInstance方法
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
       //第一个参数:类加载器
       //第二个参数:增强方法所在的类,这个类实现的接口,支持多个接口
       //第三个参数:实现接口InvocationHandler,创建代理对象,写增强的方法                                
    
    1. JDK动态代理代码实现
    //1.创建接口,定义方法
    public interface UserDao {
    public int add(int a, int b);
    public String update(String id);}
    
    //2.创建接口实现类,实现方法
    public class UserDaoImpl implements UserDao {
    @Override
    public int add(int a, int b) {
        return a+b;
    }
    @Override
    public String update(String id) {
        return id;
    }}
    
    public class JDKProxy {
    
    public static void main(String[] args) {
        //创建接口实现类代理对象
        Class[] interfaces = {UserDao.class};
        /*Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });*/
        UserDao userDao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces , new UserDaoProxy(new UserDaoImpl()));
        int result = userDao.add(1,2);
        System.out.println("result:" + result);
    }}
    
    //创建代理对象代码
    class UserDaoProxy implements InvocationHandler{
    
    //传入被代理对象
    private Object object;
    public UserDaoProxy(Object o){
        this.object = o;
    }
    
    //增强逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法之前执行
        System.out.println("方法之前执行。。。" + method.getName() + "参数"+ Arrays.toString(args));
        //被增强的方法执行
        Object res = method.invoke(object, args);
        //方法之后
        System.out.println("方法之后执行。。。"+ object);
        return res;
    }}
    
AOP(术语)
  1. 连接点:类里面哪些方法可以被增强,这些方法被称为连接点
  2. 切入点:实际被真正增强的方法,被称为切入点
  3. 通知(增强):实际增强的逻辑部分称为通知
    1. 前置通知
    2. 后置通知
    3. 环绕通知
    4. 异常通知
    5. 最终通知
  4. 切面:把通知应用到切入点的过程
AOP操作
  1. Spring框架一般都是基于AspectJ实现AOP操作,AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
  2. 基于AspectJ实现AOP操作
    1. 基于xml配置文件实现
    2. 基于注解方式实现
  3. 切入点表达式
    1. 切入点表达式作用:知道对哪个类里面的哪个方法增强
    2. 语法结构:execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
AOP操作(AspectJ注解)
  1. 创建类,定义方法
public class User {
    public void add(){
        System.out.println("add...");
    }
}
  1. 创建增强类(编写增强逻辑)
    1. 在增强类里面,创建方法,让不同方法代表不同通知类型
public class UserProxy {
    public void before(){
        System.out.println("before...");
    }
}
  1. 进行注解的配置
    1. 在配置文件中开启注解的扫描
    2. 使用注解创建User和UserProxy对象
    3. 在增强类上加上@Asect
    4. 在Spring配置文件中开启生成代理对象
  2. 配置不同类型的通知
    1. 在作为通知方法上面添加通知类型注解,使用切入点表达式配置
<context:component-scan base-package="com.wp.spring5.aopanno"></context:component-scan>
    <!--开启AspectJ生成代理对象-->
    <aop:aspectj-autoproxy ></aop:aspectj-autoproxy>

@Component
@Aspect
public class UserProxy {

    //前置通知
    @Before(value = "execution(* com.wp.spring5.aopanno.User.add(..))")
    public void before(){
        System.out.println("before...");
    }
	//最终通知,方法后执行
    @After(value = "execution(* com.wp.spring5.aopanno.User.add(..))")
    public void after(){
        System.out.println("after...");
    }
	//后置通知(返回通知),返回结果时执行
    @AfterReturning(value = "execution(* com.wp.spring5.aopanno.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning...");
    }
	//异常通知
    @AfterThrowing(value = "execution(* com.wp.spring5.aopanno.User.add(..))")
    public void afterThrowing(){
        System.out.println("AfterThrowing...");
    }
    //环绕通知
    @Around(value = "execution(* com.wp.spring5.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("Around...前置");
        proceedingJoinPoint.proceed();
        System.out.println("Around...后置");
    }
}

//运行结果
Around...前置
before...
add...
afterReturning...
after...
Around...后置

//出现异常运行结果
Around...前置
before...
AfterThrowing...
after...

java.lang.ArithmeticException: / by zero
  1. 相同的切入点抽取
//相同切入点抽取
    @Pointcut(value = "execution(* com.wp.spring5.aopanno.User.add(..))")
    public void pointdemo(){}

    //前置通知
    @Before(value = "pointdemo()")
    public void before(){
        System.out.println("before...");
    }
  1. 多个增强类对同一个方法增强,可设置优先级
    1. 在增强类上添加注解@Order(数字类型值),数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
public class PersonProxy
  1. 完全注解开发
@Configuration
@ComponentScan(basePackages = {"com.wp.spring5"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
AOP操作(AspectJ配置文件)
<!--创建对象-->
<bean id="book" class="com.wp.spring5.aopxml.Book"></bean>
    <bean id="bookProxy" class="com.wp.spring5.aopxml.BookProxy"></bean>
    <!--配置aop增强-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p" expression="execution(* com.wp.spring5.aopxml.Book.buy(..))"/>
        <!--配置切面-->
        <aop:aspect ref="bookProxy">
            <!--增强作用在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>
JdbcTemplate(概念和准备)
  1. 什么是JdbcTemplate?
    1. spring框架对jdbc进行封装,使用jdbcTemplate方便实现对数据库操作
    2. 准备工作
      在这里插入图片描述
<context:property-placeholder location="classpath:jdbc.properties"/>
    <!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${prop.driverClass}"></property>
        <property name="url" value="${prop.url}"></property>
        <property name="username" value="${prop.userName}"></property>
        <property name="password" value="${prop.password}"></property>
    </bean>
    <!--JdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入DataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
  1. JdbcTemplate数据库操作(添加)
String sql = "insert into t_book values(?, ?, ?)";
        Object[] args = {book.getUserId(), book.getUsername(), book.getUstatus()};
        int update = jdbcTemplate.update(sql, args);
  1. JdbcTemplate数据库操作(修改和删除)
@Override
    public void update(Book book) {
        String sql = "update t_book set username = ?, ustatus = ? where user_id = ?";
        Object[] args = {book.getUsername(), book.getUstatus(), book.getUserId()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }

    @Override
    public void delete(String id) {
        String sql = "delete from t_book where user_id = ?";
        int update = jdbcTemplate.update(sql, id);
        System.out.println(update);
    }
  1. JdbcTemplate数据库操作(查询返回某个值)
@Override
    public int selectCount() {
        String sql = "select count(*) from t_book";
        return jdbcTemplate.queryForObject(sql, Integer.class);
    }
  1. JdbcTemplate数据库操作(查询返回对象)
//RowMapper:是接口,返回不同类型数据,使用这个接口里面实现类完成数据封装
<T> T queryForObject(String var1, RowMapper<T> var2, Object... var3) throws DataAccessException;

@Override
    public Book findBookInfo(String id) {
        String sql = "select * from t_book where user_id = ?";
        return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
    }
  1. JdbcTemplate数据库操作(查询返回集合)
@Override
    public List<Book> findAllBook() {
        String sql = "select * from t_book";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
    }
  1. JdbcTemplate数据库操作(批量操作)
//批量新增
@Override
    public void batchAddBook(List<Object[]> batchArgs) {
        String sql = "insert into t_book values(?, ?, ?)";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }
//批量修改
@Override
    public void batchUpdateBook(List<Object[]> batchArgs) {
        String sql = "update t_book set username = ?, ustatus = ? where user_id = ?";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }
//批量删除
@Override
    public void batchDeleteBook(List<Object[]> batchArgs) {
        String sql = "delete from t_book where user_id = ?";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }

事务概念
  1. 什么是事务
    1. 事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
  2. 事务四个特性(ACID)
    1. 原子性
    2. 一致性
    3. 隔离性
    4. 持久性
  3. 在Spring进行事务管理操作
    1. 两种方式:编程式事务管理(代码中开启提交事务)和声明式事务管理
  4. 声明式事务管理
    1. 基于注解方式
    2. 基于xml配置文件方式
  5. 在Spring进行声明式事务管理,底层使用AOP
  6. Spring事务管理API
    1. 提供一个接口,代表事务管理器,这个接口针对不同框架提供不同的实现类
事务操作(注解声明式事务管理)
  1. 在spring配置文件配置事务管理器
<!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
  1. 在spring配置文件中,开启事务注解
<!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
  1. 在service类上(或者service类里面的方法上面)添加事务注解@Transactional
    1. 如果添加在类上面,这个类里面所有的方法都添加事务
    2. 如果添加在方法上面,为这个方法添加事务
事务操作(声明式事务管理参数配置@Transactional)
  1. propagation:事务传播行为

    1. 多事务方法直接进行调用,这个过程中事务是进行怎样管理的
      在这里插入图片描述
  2. isolation: 事务隔离级别

    1. 事务特性(隔离性),多事务操作之间不会产生影响,不考虑隔离性会产生很多问题
    2. 三个读问题:脏读,不可重复读,幻读
    3. 脏读:一个未提交事务读取到另一个未提交事务的数据
    4. 不可重复读:一个未提交事务读取到另一个提交事务修改的数据
    5. 幻读:一个未提交事务读取到另一个提交事务添加的数据
    6. 解决:通过设置事务隔离级别,解决读 的问题
      在这里插入图片描述
  3. timeout:超时时间

    1. 事务需要在一定时间内进行提交,如果不提交进行回滚
    2. 默认值是-1,设置时间以秒单位进行计算
  4. readOnly:是否只读

    1. 读:查询操作,写:添加修改删除操作
    2. readOnly默认值false,表示可以查询,可以添加修改删除操作
    3. 设置readOnly值为true,只能查询
  5. rollbackFor:回滚

    1. 设置出现哪些异常进行事务回滚
  6. noRollbackFor:不回滚

    1. 设置出现哪些异常不进行事务回滚
@Service
@Transactional(rollbackFor = ClassNotFoundException.class,readOnly = false, timeout = -1, propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
public class UserService {}
事务操作(XML声明式事务管理)
<!--1.创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!--2.配置通知-->
    <tx:advice id="txadvice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定那种规则的方法上面添加事务-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
            <!--<tx:method name="account*"/>-->
        </tx:attributes>
    </tx:advice>
    
    <!--3.配置切入点和切面-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.wp.spring5.service.UserService.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
    </aop:config>
事务操作(完全注解声明式事务管理)
  1. 创建配置类,使用配置类替代xml配置文件
@Configuration  //配置类
@ComponentScan(basePackages = "com.wp.spring5")  //组件扫描
@EnableTransactionManagement  //开启事务
public class TxConfig {

    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
        dataSource.setUsername("contact");
        dataSource.setPassword("contact");
        return dataSource;
    }

    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        //到ioc容器汇中根据类型找到dataSource
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值