Aop切面编程

spring Aop切面编程

Aop中的概念

target:目标类,即需要被代理的类

join-point:连接点:指的是那些有可能被拦截到的方法

pointcut:切入点,指的是已经被增强的连接点

advice:通知,增强的代码

weaving:织入,把advice织入到target创建proxy的过程

aspect:切面,是切入点和通知的结合

两种方式实现Aop切面编程:

基于xml方式的切面编程(以jdk动态代理为例)

1.首先需要定义切面类:里面是通知,即增强代码
public class MyAspect1 {
    public void classId(){
        System.out.println("这是zzj190703班的大神们:");
    }
    public void totalCount(){
        System.out.println("zzj190703班共23人!");
    }
    public void afterReturn(Object message){
        System.out.println("更新数据!"+ message);
    }
    public  Object around(ProceedingJoinPoint joinPoint) {
        Object ret = null;
        try {
            ret = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("[环绕通知]这真是充实的一天, 早睡早起,方能养生!");
        return ret;
    }
}
2.在定义一个接口和一个实现类

接口

public interface StudentDao {
    List<Student> findAllStudent();
    int updateStudent();
}

3.实现类(目标类,即需要被代理的类):

里面的每一个方法都是一个连接点,被拦截到的点织入增强代码的点称为切入点

/**
 * 这是xml方式的AOP
 */
public class StudentDaoImpl2 implements StudentDao  {
    @Autowired
    private QueryRunner queryRunner;
    @Override
    public List<Student> findAllStudent() {
        String sql = "select * from student";
        List<Student> studentList = null;
        try {
            studentList = queryRunner.query(sql,new BeanListHandler<Student>(Student.class));
            return studentList;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    @Override
    public int updateStudent() {
        String sql = "update student set sage=48 where sage=?";
        try {
            int num =  queryRunner.update(sql,120);
            return num;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }

}
4.最后配置xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       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
        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 https://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.lanou" />
    <context:property-placeholder location="jdbc.properties" />
    <!--切面类:里面是通知,即要增强的代码-->
    <bean id="myAspect" class="com.lanou.aspect.MyAspect1" />

    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" autowire="constructor" />

    <bean id="studentDao" class="com.lanou.dao.daoImpl.StudentDaoImpl2" autowire="byType"/>

<!--切面编程的配置-->
    <aop:config>
        <!--切入点的定义:里面有切入点表达式,即要拦截的方法-->
        <aop:pointcut id="classid" expression="execution(* com.lanou.dao.daoImpl.StudentDaoImpl2.findAllStudent(..))"/>
        <!--切面的定义:由切入点和通知组成-->
        <aop:aspect ref="myAspect">
            <aop:before method="classId" pointcut-ref="classid" />
            <aop:around method="around" pointcut-ref="classid" />
            <aop:after-returning method="afterReturn" pointcut-ref="classid" returning="message" />
        </aop:aspect>
    </aop:config>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
        <property name="driverClassName" value="${jdbc.driver}" />

        <property name="filters" value="stat" />

        <property name="maxActive" value="20" />
        <property name="initialSize" value="1" />
        <property name="maxWait" value="60000" />
        <property name="minIdle" value="1" />

        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />

        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />

        <property name="poolPreparedStatements" value="true" />
        <property name="maxOpenPreparedStatements" value="20" />

        <property name="asyncInit" value="true" />
    </bean>
    <!--方法一:-->
    <!--  <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" c:ds-ref="dataSource" /> -->
    <!--方法er-->
</beans>

需要注意的是:切面类和切面是不一样,切面类:里面定义的是通知方法,切面:是拦截连接点中指定的连接点(所拦截的连接点此时称为切入点)和通知组成.

基于注解的AOP

1.需要的依赖
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.2</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.0.RELEASE</version>
    </dependency>

  <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.20</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
  <dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.7</version>
  </dependency>
 <!-- https://mvnrepository.com/artifact/cglib/cglib -->
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.3.0</version>
    </dependency>
2.定义切面类
/**
 * 这是注解的方式AOP
 * 这是切面类
 */
@Aspect
@Component
public class MyAspect {
    @Before("com.lanou.pointCut.MyPointCut.findAllStudent()")
    public void classId(){
        System.out.println("这是zzj190703班的大神们:");
    }

    @AfterReturning(value = "com.lanou.pointCut.MyPointCut.returnning()",returning = "message")
    public void afterReturn(Object message){
        System.out.println("更新数据!"+ message);
    }

    @After("com.lanou.pointCut.MyPointCut.findAllStudent()")
    public void totalCount(){
        System.out.println("zzj190703班共23人!");
    }
}
3.切入点
public class MyPointCut {
    @Pointcut("execution(* findAllStudent(..))")
    public void findAllStudent(){
    }
    @Pointcut("execution(public * com.lanou.dao.daoImpl.*.updateStudent(..))")
    public void returnning(){
    }
}
4.然后是配置类
@Configuration
@ComponentScan(basePackages = "com.lanou")
@EnableAspectJAutoProxy
@PropertySource("classpath:jdbc.properties")
public class MyConfiguration {
    @Value("${jdbc.user}")
    private String user;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.driver}")
    private String driver;
    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername(user);
        dataSource.setUrl(url);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driver);
        return dataSource;
    }
    @Bean
    public QueryRunner queryRunner(){
        return new QueryRunner(dataSource());
    }
}
5.接口
public interface StudentDao {
    List<Student> findAllStudent();
    int updateStudent();
}
6.实现
/**
 * 这是注解的方式AOP
 */
public class StudentDaoImpl1 implements StudentDao  {
    @Autowired
    private QueryRunner queryRunner;
    @Override
    public List<Student> findAllStudent() {
        String sql = "select * from student";
        List<Student> studentList = null;
        try {
            studentList = queryRunner.query(sql,new BeanListHandler<Student>(Student.class));
            return studentList;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    @Override
    public int updateStudent() {
        String sql = "update student set sage=120 where sage=?";
        try {
            int num =  queryRunner.update(sql,48);
            return num;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }
}

注意上面的切面通知类和切入点还有目标类之间的对应关系.

关于AOP切面编程的原理

jdk动态代理模式

必要的配置

@Configuration
@ComponentScan(basePackages = "com.lanou")
@EnableAspectJAutoProxy
@PropertySource("classpath:jdbc.properties")
public class MyConfiguration {
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.user}")
    private String user;
    @Value("${jdbc.driver}")
    private String driver;

    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        dataSource.setPassword(password);
        dataSource.setUsername(user);
        return dataSource;
    }
    @Bean
    public QueryRunner queryRunner(){
        return new QueryRunner(dataSource());
    }
}

1.定义切面

@Aspect
@Component
public class MyAspect {
    public void befor(){
        System.out.println("我在前面!");
    }
    public void after(){
        System.out.println("我在后面!");
    }
}

2.目标类的定义

一个接口
public interface StudentDao {
    List<Student> findAllStudent();
    void updateStudent();
    void deleteStudent()
}
一个实现类
@Repository
public class StudentDaoImpl  implements StudentDao {
    @Autowired
    private QueryRunner queryRunner;
    @Override
    public List<Student> findAllStudent() {
        String sql = "select * from student where sage=?;";
        try {
            List<Student> studentList = queryRunner.query(sql, new BeanListHandler<Student>(Student.class),25);
            return studentList;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    @Override
    public void updateStudent() {
        System.out.println("更新学生的信息!");
    }

    @Override
    public void deleteStudent() {
        System.out.println("删除学生的信息!");
    }
}

3.jdk动态代理

/**
 * 原理:创建一个新的对象,实现目标表类的所有接口
 */
public class MyBeanFactoryJdk {

    public static StudentDao createStudentDao(){
        //1.需要一个目标类
        StudentDao studentDao = new StudentDaoImpl();
        //2.需要一个切面类
         MyAspect aspect = new MyAspect();
        //3.生成切面,即生成代理:
        StudentDao proxyStudentDao = (StudentDao) Proxy.newProxyInstance(MyBeanFactoryJdk.class.getClassLoader(), studentDao.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                aspect.befor();
                Object obj = method.invoke(studentDao, args);
                aspect.after();
                return obj;
            }
        });
        return proxyStudentDao;
    }
}

cglib代理方式

上面的都一样只有代理部分不一样

/**
 * 原理:创建目标类的子类
 */
public class MyBeanFactoryCglib {
    public static StudentDao createStudentDao(){
        //目标类
        StudentDao studentDao = new StudentDaoImpl();
        //切面类
        MyAspect aspect = new MyAspect();
        //cglib里面的核心类Enhancer
        //1:创建Enhancer的对象
        Enhancer enhancer = new Enhancer();
        //2.选择继承的父类
        enhancer.setSuperclass(studentDao.getClass());
        //3.回调函数
       enhancer.setCallback(new MethodInterceptor() {
           @Override
           public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
               aspect.befor();
               Object obj = method.invoke(studentDao,objects);
               aspect.after();
               return obj;
           }
       });
       StudentDao proxyStudentDao = (StudentDao) enhancer.create();
        return proxyStudentDao;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值