Spring Aop

一、代理模式

代理模式的两个设计原则

  • 代理类与委托类具有相似的行为
  • 代理类增强委托类的行为

1、静态代理

2、动态代理

(1)、jdk实现动态代理

回调方式实现
原理: 基于接口实现
局限: 很多类没有实现接口, 那么jdk就无法实现代理

package com.shsxt.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * jdk 动态代理
 *
 */
public class JdkHandler implements InvocationHandler{
    
    // 目标类
    private Object target;
    
    public JdkHandler(Object target) {
        this.target = target;
    }
    
    /**
     * 程序运行期动态创建代理角色
     * @return
     */
    public Object getProxy(){
        /**
         * 获取代理对象
         * 1.类加载器
         * 2.目标类 实现的接口 class
         * 3.当前类
         * @return
         */
        return Proxy.newProxyInstance(
                this.getClass().getClassLoader(),
                target.getClass().getInterfaces(), 
                this
        );
    }
    
    public void before(){
        System.out.println("婚礼现场紧张布置中......");
    }
    public void after(){
        System.out.println("恭喜您成功进入人生第二阶段.....");
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        before();//增强真实角色行为
        Object result= method.invoke(target, args);// 执行真实角色方法
        after();//增强真实角色行为
        return result;
    }   

}

测试类

package com.shsxt.jdk;

import com.shsxt.You;
import org.junit.Test;

import static org.junit.Assert.*;

/**
 * Created by xlf on 2019/7/6.
 */
public class JdkHandlerTest {
    @Test
    public void invoke() throws Throwable {

        You you = new You();

        JdkHandler jdkHandler = new JdkHandler(you);
        Object proxy = jdkHandler.getProxy();// 创建代理角色

        jdkHandler.invoke(proxy, You.class.getMethod("toMarry"),null);

    }

}

(2)、cglib动态代理实现

code generator library,操作字节码。
原理: 基于继承思想
作用: 针对没有实现接口的类,进行代理

与jdk提供的代理区别,Proxy:委托类必须有接口,制作过程比较快,执行慢;cglib:委托类可以没有接口,继承的思维来实现相似性,制作代理过程比较慢,执行快。主要解决没有接口类的代理实现。

package com.shsxt.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibInterceptor implements MethodInterceptor {
    private Object target;

    public CglibInterceptor(Object target) {
        this.target = target;
    }
    
    // 运行期动态创建代理类
    public Object getProxy(){
        Enhancer enhancer=new Enhancer();
        //设置父类 class
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return  enhancer.create();
    }

    public void before(){
        System.out.println("婚礼现场紧张布置中......");
    }
    @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2,
            MethodProxy arg3) throws Throwable {
        before();//增强真实角色行为
        Object result= arg3.invoke(target, arg2);
        after();//增强真实角色行为
        return result;
    }
    public void after(){
        System.out.println("恭喜您成功进入人生第二阶段.....");
    }
}

测试类

package com.shsxt.cglib;

import com.shsxt.You;
import org.junit.Test;

import static org.junit.Assert.*;

/**
 * Created by xlf on 2019/7/6.
 */
public class CglibInterceptorTest {
    @Test
    public void intercept() throws Exception {

        You you = new You();

        CglibInterceptor cglibInterceptor = new CglibInterceptor(you);

        You proxy = (You) cglibInterceptor.getProxy();

        proxy.toMarry();

    }

    @Test
    public void intercept02() throws Exception {
        You proxy = (You) new CglibInterceptor(new You()).getProxy();
        proxy.toMarry();
    }

}

二、Aop(jdk+cglib)

概念

Aspect Oriented Programing 面向切面编程,相比较 oop 面向对象编程来 说,Aop 关注的不再是程序代码中某个类,某些方法,而 aop 考虑的更多的是一种面到面 的切入 即层与层之间的一种切入,所以称之为切面。

1、Joinpoint(连接点)

被拦截到的每个点,spring 中指被拦截到的每一个方法,spring aop 一个连接点即代表一个方法的执行。

2、Pointcut(切入点)

对连接点进行拦截的定义(匹配规则定义 规定拦截哪些方法,对哪些方 法进行处理),spring 这块有专门的表达式语言定义。

3、Advice(通知)

拦截到每一个连接点即(每一个方法)后所要做的操作
i. 前置通知 (前置增强) --before() 执行方法前通知
ii.返回通知(返回增强)–afterReturn 方法正常结束返回后的通知
iii.异常抛出通知(异常抛出增强)–afetrThrow()
iv.最终通知—after 无论方法是否发生异常,均会执行该通知。
v.环绕通知—around 包围一个连接点(join point)的通知,如方法调用。 这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也 会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

4、Aspect(切面)

切入点与通知的结合,决定了切面的定义,切入点定义了要拦截哪些类的 哪些方法,通知则定义了拦截过方法后要做什么,切面则是横切关注点的抽象, 与类相似,类是对物体特征的抽象,切面则是横切关注点抽象。

5、Target(目标对象)

被代理的目标对象

6、Weave(织入)

将切面应用到目标对象并生成代理对象的这个过程即为织入。

7、Introduction(引入)

在不修改原有应用程序代码的情况下,在程序运行期为类动态添加方法或 者字段的过程称为引入

三、使用 Aop 解决日志处理问题

方式一:注解方式

1、jar包坐标引入


  org.aspectj
  aspectjweaver
  1.8.9

2、spring.xml配置

添加命名空间

xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">

配置aop代理


3、编写业务代码

4、编写aop实现类

package com.shsxt;

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

/**
 * Created by xlf on 2019/7/6.
 */
@Aspect
@Component
public class LogCut {

    // 定义切入点
    // 拦截规则
    @Pointcut("execution (* com.shsxt.service..*.*(..))")
    public void cut() {
    }

    @Before("cut()")
    public void before() {
        System.out.println("before");
    }

    @After("cut()")
    public void after() {
        System.out.println("after");
    }

    @AfterReturning("cut()")
    public void afterReturning() {
        System.out.println("afterReturning");
    }

    @AfterThrowing(pointcut = "cut()", throwing = "e")
    public void afterThrowing(Exception e) {
        System.out.println("AfterThrowing");
        System.out.println(e);
    }

    @Around("cut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around -- before");
        Object result = pjp.proceed();
        System.out.println("around -- after");
        return result;
    }


}

方式二:xml配置实现

1、声明aop代理


2、配置切面、切入点、通知



    
        
        
        
        
        
        
    

3、定义bean

package com.shsxt;

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

/**
 * Created by xlf on 2019/7/6.
 */
@Component
public class LogCut2 {

    public void cut() {
    }

    public void before() {
        System.out.println("before==2");
    }

    public void after() {
        System.out.println("after==2");
    }

    public void afterReturning() {
        System.out.println("afterReturning==2");
    }

    public void afterThrowing(Exception e) {
        System.out.println("afterThrowing==2");
        System.out.println(e);
    }

    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around -- before==2");
        Object result = pjp.proceed();
        System.out.println("around -- after==2");
        return result;
    }


}

你可能感兴趣的:(java,框架)