Spring之AOP面向切面编程和JDBC

一、动态代理Proxy:

利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象),代理的是接口(Interfaces),不是类(Class),也不是抽象类。在运行时才知道具体的实现,spring aop就是此原理。
一:写一个接口:

package com.openlab.dao;
public interface UserDao {
    public int add(int a,int b);
}

接着写一个类实现接口:

package com.openlab.dao.Impl;
import com.openlab.pojo.PeoPle;
import lombok.Data;
import org.springframework.stereotype.Component;
@Component
@Data
public class PeopleDao {
    public void save(){
        System.out.println("PeopleDao中的实现类1---save");
    }
    public Integer test(int a,int b){
        System.out.println("PeopleDao实现类执行了------加法运算");
        return a+b;
    }
}

测试类,写了一个InvocationHandler内部类
也可以写一个写一个类实现InvocationHandler接口:
我写的是第一种内部类方式:

package com.openlab;
import com.openlab.dao.Impl.UserDaoImpl;
import com.openlab.dao.UserDao;
import com.openlab.config.Springconfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(Springconfig.class);

        final UserDaoImpl userDao = new UserDaoImpl();
        Class[] interfaces = userDao.getClass().getInterfaces();
        UserDao o = (UserDao) Proxy.newProxyInstance(MyTest.class.getClassLoader(), interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("方法执行前:"+method.getName()+"......."+ Arrays.toString(args));
                Object invokes = method.invoke(userDao,args);
                System.out.println("方法执行之后");
                return invokes;
            }
        });
        int add = o.add(3, 5);
        System.out.println(add);
    }
}

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

第一个参数(ClassLoader loader 表示用哪个类的加载器
第二参数Class<?>[] interfaces 动态类需要实现的接口个数
第三参数InvocationHandler h 动态代理方法在执行时,会调用h里面的invoke方法去执行
返回类型是Object类型,需要强转为我们需要的接口类型;

上面代码中,代理u对象,调用UserDao中的add方法时,自动执行InvocationHandler中的invoke方法。

测试结果:

在这里插入图片描述

spring aop

  1. 连接点:类里面那些方法可以被增强,这些方法称为连接点
  2. 切入点:实际被增强的方法
  3. 通知:实际增强的逻辑部分 类型:前置通知 后置通知 环绕通知 异常通知 最终通知
  4. 切面:动作,把通知应用到切入点过程
通过注解方式

aop注解:
Advice(通知、切面): 某个连接点所采用的处理逻辑,也就是向连接点注入的代码, AOP在特定的切入点上执行的增强处理。
@Before: 标识一个前置增强方法,相当于BeforeAdvice的功能.
@After: final增强,不管是抛出异常或者正常退出都会执行.
@AfterReturning: 后置增强,似于AfterReturningAdvice, 方法正常退出时执行.
@AfterThrowing: 异常抛出增强,相当于ThrowsAdvice.
@Around: 环绕增强,相当于MethodInterceptor.

表达式标签

表达式标签
execution():用于匹配方法执行的连接点
args(): 用于匹配当前执行的方法传入的参数为指定类型的执行方法
this(): 用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
target(): 用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
within(): 用于匹配指定类型内的方法执行;
@args():于匹配当前执行的方法传入的参数持有指定注解的执行;
@target():用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
@within():用于匹配所以持有指定注解类型内的方法;
@annotation:用于匹配当前执行方法持有指定注解的方法;

PeoPleDaoProxy 类

package com.openlab.dao.proxy;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class PeoPleDaoProxy {
    @Pointcut(value="execution(* com.openlab.*.*.*(..))")//Pointcut(切入点):
    //  JoinPoint的集合,是程序中需要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。
    public void Poin(){

    }
    @Before(value = "execution(* com.openlab.dao.Impl.PeopleDao.*())")  //前置通知
    public void before(){
        System.out.println("方法执行前");
    }
    @After(value = "execution(* com.openlab.dao.Impl.PeopleDao.*())")  //后置通知
    public void after(){
        System.out.println("方法执行后");
    }
        @AfterReturning(value = "execution(* com.openlab.dao.Impl.PeopleDao.*())")
    public void afterReturning(){
        System.out.println("最终执行");
    }
    @AfterThrowing(value="Poin()")//异常通知
    public void aferthrow(){
        System.out.println("出异常了");
    }
    @Around(value = "execution(* com.openlab.dao.Impl.PeopleDao.*())")  //环绕通知
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("执行之前环绕");
        joinPoint.proceed();
        System.out.println("执行之后环绕");
    }
}

调用类:

package com.openlab.dao.Impl;

import com.openlab.pojo.PeoPle;
import lombok.Data;
import org.springframework.stereotype.Component;

@Component
@Data
public class PeopleDao {
    public void save(){
        System.out.println("PeopleDao中的实现类1---save");
    }
    public Integer Update(PeoPle people){
        System.out.println("PeopleDao实现类执行了:"+people);
        return 10;
    }
    public Integer test(int a,int b){
        System.out.println("PeopleDao实现类执行了------加法运算");
        try{
            int month=1/0;
        }catch(Throwable e){
            System.err.println("方法出错");
        }finally {
            System.out.println("方法的finally");
        }
        return a+b;
    }
}

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: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
       https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
       
    <context:component-scan base-package="com.openlab"/>
    <aop:aspectj-autoproxy /> //重点

</beans>

测试类

package com.openlab;
import com.openlab.dao.Impl.PeopleDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ProxyTest {
    @Test
    public void test01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        PeopleDao peopleDao = context.getBean(PeopleDao.class);
        peopleDao.save();
        Integer test = peopleDao.test(5, 7);
        System.out.println(test);
    }
}

测试结果:
在这里插入图片描述

注解方式类型的顺序:

环绕前通知 前置通知 (运行方法) 异常通知 最终通知 后置通知 环绕后通知

xml配置方式
<aop:aspectj-autoproxy />
所以我们只需要把aop:aspectj-autoproxy</aop:aspectj-autoproxy>注释掉,切面类的注释方式就失效了。所以我就只修改了xml的配置:

   <!--声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,如果没有就不能使用注解方式-->
    <context:component-scan base-package="com.openlab" ></context:component-scan>
    <!--扫描-->
    <bean id="PeoPleDaoProxy" class="com.openlab.dao.proxy.PeoPleDaoProxy"></bean>
    <!--配置找到切面类-->
    <aop:config>
        <aop:pointcut expression="execution(* com.openlab.*.*.*(..))" id="poin"/><!--连接点-->
        <aop:aspect ref="PeoPleDaoProxy"><!--配置切面类是谁-->
            <aop:before method="before" pointcut-ref="poin"></aop:before><!--配置找到切面类的前置通知方法类型-->
            <aop:after method="after" pointcut-ref="poin"></aop:after>
            <aop:after-returning method="afterReturning" pointcut-ref="poin"/>
            <aop:after-throwing method="aferthrow"  pointcut-ref="poin"/>
            <aop:around method="around" pointcut-ref="poin"/>
        </aop:aspect>
    </aop:config>

我们发现xml配置类型的顺序和注解方式顺序不一样;最后发现是xml中。

Spring-JDBC

首先:pom.xml引入依赖

<!--JDBC-->
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.5</version>
        </dependency>
<!--MYSQL-->
  		  <dependency>
 	 		  <groupId>mysql</groupId>
  			  <artifactId>mysql-connector-java</artifactId>
  			  <version>8.0.26</version>
		</dependency>

在准备db.properties

#\u8FDE\u63A5\u8BBE\u7F6E
//com.mysql.jdbc.Driver 是 mysql-connector-java 5中的, 
//com.mysql.cj.jdbc.Driver 是 mysql-connector-java 6后的
jdbc.driverClassName=com.mysql.cj.jdbc.Driver//我的mysql数据库是8.26的所以是com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/t1				//jdbc:mysql: 是指JDBC连接方式;localhost: 是指你的本机地址
jdbc.name=root            //用户名          
jdbc.password=root  //密码

创建数据库对应的类
在这里插入图片描述

package com.openlab.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Classes {
    private int id;
    private String mnane;
    private int sums;
}

dao包建接口:

package com.openlab.dao;

import com.openlab.pojo.Classes;

public interface ClassesDao {
        public int add(Classes role);//添加
        public int updat(Classes role);//更新
        public int delete(int roleid);//删除
}

Impl包里创建类实现接口:

package com.openlab.dao.Impl;

import com.openlab.dao.ClassesDao;
import com.openlab.pojo.Classes;
import org.springframework.jdbc.core.JdbcTemplate;

public class ClassDaoImpl implements ClassesDao {
    private JdbcTemplate jdbcTemplate;
    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    @Override
    public int add(Classes classes) {
        String sql="insert into class(id,mnane,snums) value(?,?,?)";
        // 定义数组来存放SQL语句中的参数
        Object[] obj = new Object[] {classes.getId(),classes.getMnane(),classes.getSums()};
        // 执行添加操作,返回受SQL语句影响的条数
        int num = this.jdbcTemplate.update(sql, obj);
        return num;
    }
    @Override
    public int updat(Classes classes) {
        String sql="update into class(id,mnane,snums) value(?,?,?)";
        // 定义数组来存放SQL语句中的参数
        Object[] obj = new Object[] {classes.getId(),classes.getMnane(),classes.getSums()};
        // 执行添加操作,返回受SQL语句影响的条数
        int num = this.jdbcTemplate.update(sql, obj);
        return num;
    }
    @Override
    public int delete(int id) {
        // 定义SQL
        String sql = "delete from class where id=?";
        // 执行更新操作,返回受SQL语句影响的条数
        int num=this.jdbcTemplate.update(sql,id);
        return num;
    }
}

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

    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <!-- 1.配置数据源 -->
    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <!-- 数据库驱动 -->
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <!--连接数据库的url -->
        <property name="url" value="${jdbc.url}"></property>
        <!--连接数据库的用户名 -->
        <property name="username" value="${jdbc.name}"></property>
        <!--连接数据库的密码 -->
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <bean id="jdbcTemplate"
          class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 默认必须使用数据源 -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <bean id="classImpl" class="com.openlab.dao.Impl.ClassDaoImpl">
        <!-- 将jdbcTemplate注入到accountDao实例中 -->
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
</beans>

测试类:

package com.openlab;

import com.openlab.dao.Impl.ClassDaoImpl;
import com.openlab.pojo.Classes;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Testclass {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans2.xml");
        ClassDaoImpl classimpl = context.getBean("classImpl", ClassDaoImpl.class);
        Classes lala = new Classes(10, "拉拉", 38);
        int adds = classimpl.add(lala);
        if(adds>0) {
            System.out.println("成功插入"+adds+"条数据!");
        }else {
            System.out.println("插入操作执行失败");
        }
    }
}

插入结果:
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值