Spring学习笔记(三)——代理模式和AOP

文章目录

      • 六、代理模式
        • 6.1 静态代理模式
        • 6.2 动态代理模式
      • 七、AOP
        • 7.1 什么是AOP
        • 7.2 核心概念
        • 7.3 Spring实现AOP
        • 7.4 注解实现AOP

六、代理模式

SpringAOP的底层

6.1 静态代理模式

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色(房东)
  • 代理角色:代理真实角色,做一些附属操作(中介)
  • 客户:访问代理角色的人(租客)

静态代理的好处:

  • 可以使真实角色的操作更纯粹,不用去关注一些公共的事务
  • 实现了业务的分工
  • 公共业务发生扩展时,方面集中处理

缺点:一个真是角色就会产生一个代理角色,代码量翻倍,开发效率低

6.2 动态代理模式

在这里插入图片描述
Spring学习笔记(三)——代理模式和AOP_第1张图片

rent接口

public interface Rent {
    public void rent();
}

Host类

public class Host implements Rent{

    public void rent() {
        System.out.println("房东出租房子");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//这个类用于自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    //处理代理实例,并返回结果
    //当调用代理代理对象的方法时,
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(target, args);
        return invoke;
    }

}

客户类

public class Client {
    public static void main(String[] args) {
        //真实对象
        Host host = new Host();

        //代理对象
        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        //设置要代理的对象
        pih.setTarget(host);

        //获得代理
        Rent proxy = (Rent)pih.getProxy();

        proxy.rent();
    }

}

动态代理的好处:

  • 可以使真实角色的操作更加纯粹
  • 公共业务交给了代理角色
  • 方便扩展公共业务
  • 一个动态代理类对应的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要实现了同一个接口

七、AOP

7.1 什么是AOP

AOP,英文全称Aspect Oriented Propramming ,以为面向切面编程

Spring学习笔记(三)——代理模式和AOP_第2张图片

AOP在Spring中的作用:提供生命式事务;允许用户自定义切面

7.2 核心概念

  • 横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

  • 切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象

  • 连接点(joinpoint):被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

  • 切入点(pointcut):对连接点进行拦截的定义

  • 通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类

  • 目标对象:代理的目标对象,被通知对象

  • 织入(weave):将切面应用到目标对象并导致代理对象创建的过程

  • 引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

Spring学习笔记(三)——代理模式和AOP_第3张图片

7.3 Spring实现AOP

依赖

        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjweaverartifactId>
            <version>1.9.4version>
        dependency>

UserService接口

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

UserServiceImp类

public class UserServiceImp implements UserService{
    public void add() {
        System.out.println("增加一个用户");
    }

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

    public void update() {
        System.out.println("修改一个用户");
    }

    public void query() {
        System.out.println("查询一个用户");
    }
}

前置方法 继承MethodBeforeAdvice接口,实现before函数

package Log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeLog implements MethodBeforeAdvice {

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

后置方法

package Log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {

    //returnValue 返回值
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("成功执行了" + method.getName() + "方法,返回结果为" + returnValue);
    }
}

第一种方式:


<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 id="userService" class="UserServiceImp"/>
    <bean id="beforeLog" class="Log.BeforeLog"/>
    <bean id="afterLog" class="Log.AfterLog"/>

    方式一:使用原生Spring API接口
    <aop:config>
        
        <aop:pointcut id="log" expression="execution(* UserServiceImp.*(..))"/>

        
        <aop:advisor advice-ref="beforeLog" pointcut-ref="log"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="log"/>
    aop:config>

beans>

execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?) 除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。

execution()是最常用的切点函数,其语法如下所示:

整个表达式可以分为五个部分:

1、execution(): 表达式主体。

2、第一个*号:表示返回类型,*号表示所有的类型。

3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。

4、第二个*号:表示类名,*号表示所有的类。

5、*(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

execution(* UserServiceImp.*(…))

  • 第一个* 代表可以返回任意类型
  • 第二个参数是包名
  • .*表示当前包下的所有方法
  • (…)代表任意参数

第二种方式


    <bean id="cutPoint" class="PointCut"/>
    
    <aop:config>
        
        <aop:aspect ref="cutPoint">
        
            <aop:pointcut id="point" expression="execution(* UserService.*(..))"/>
            
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        aop:aspect>
    aop:config>

测试

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Mytest {

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //动态代理代理的是接口
        UserService userService = (UserService) context.getBean("userService");

        userService.delete();
    }
}

7.4 注解实现AOP

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect //切面
public class AnnotationPointCut {

    @Before("execution(* UserServiceImp.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }

    @After("execution(* UserServiceImp.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }

    @Around("execution(* UserServiceImp.*(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前");
        Object proceed = proceedingJoinPoint.proceed();//执行方法
        System.out.println("环绕后");

        System.out.println(proceed);
    }

}

配置

	
    <bean id="annotation" class="AnnotationPointCut"/>
    
    <aop:aspectj-autoproxy/>

Spring学习笔记(三)——代理模式和AOP_第4张图片

你可能感兴趣的:(Spring)