AOP动态代理之切面编程

spring中,AOP是第二特色,底层的实现就是基于动态代理,包括jdk代理和cglib代理.废话不多说,直接自己来时间一把。

jdk代理:也就是接口代理。

第一步:创建接口:略,详见IOC篇

第二步:创建接口的实现:详见IOC篇

第三步:创建jdk代理类

package com.pian.design.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Auther: Administrator
 * @Date: 2020/2/11 0011 20:39
 * @Description:
 */
public class JdkUtilProxy {

    public static Object getProxy(final Object target){

        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler(){
                    //proxy,就是返回的object
                    //method,目标对象的方法
                    //args,目标方法的参数
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("proxy 记录日志");
                        return method.invoke(target,args);
                    }
                });
    }
}

第四步:测试test1方法

package com.pian;

import com.pian.design.Factory.MyBeanFactory;
import com.pian.design.proxy.CglibUtilProxy;
import com.pian.design.proxy.JdkUtilProxy;
import com.pian.dto.User;
import com.pian.service.TestIocService;
import com.pian.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Auther: Administrator
 * @Date: 2020/2/11 0011 20:44
 * @Description:
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {App.class})
public class TestProxy {

    private TestIocService iocService = (TestIocService)MyBeanFactory.getBean("testIocService");

    @Autowired
    private UserService userService;


    @Test
    public void test1(){
        //使用jdk代理,iocService目标对象
        TestIocService proxy = (TestIocService)JdkUtilProxy.getProxy(iocService);

        //使用代理执行
        proxy.save();
    }

    @Test
    public void test2(){
        //使用cglib代理,userService目标对象,无接口实现
        UserService proxy = (UserService)CglibUtilProxy.getProxy(userService,UserService.class);
        //使用代理执行
        User user =proxy.selectById(2);
        System.out.println(user);
    }
}

cglib代理

第一步:创建实现类:略

第二步:创建cglib代理:

package com.pian.design.proxy;

import com.pian.service.UserService;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Auther: Administrator
 * @Date: 2020/2/11 0011 20:53
 * @Description:
 */
public class CglibUtilProxy {

    public static Object getProxy(Object target,Class targetClz){
        System.out.println("target.getClass():" + target.getClass());
        return Enhancer.create(targetClz, new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("CglibUtilProxy 记录日志");
                return method.invoke(target,args);
            }
        });
    }
}

第三步:测试test2方法,见上图

是不是超简单,那理解了原理,当然要运用下,spring中给我们提供aop。

AOP编程:

第一步:引入AOP包

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

第二步:编写aspect类,这个类其实和一般类没什么区别,就是用来织入的。

在类上加上@Aspect 注解,表示是切面类,@Componet可以被扫描,

这里方法recodeLog就是通知,@Around就是要切入的方法,比如UserService下所有的方法。

我们的切面=通知+切入点

package com.pian.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @Auther: Administrator
 * @Date: 2020/2/11 0011 20:19
 * @Description:
 */
@Component
@Aspect
@Slf4j
public class MyAspect {

    @Around("execution(public * com.pian.service.UserService.*(..))")
    public void recodeLog(ProceedingJoinPoint jp){
        String methodName = jp.getSignature().getName();

        Object result = null;
        try {
            log.info("【环绕增强中的--->前置增强】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
            //执行目标方法
            result = jp.proceed();
            log.info("【环绕增强中的--->返回增强】:the method 【" + methodName + "】 ends with " + result);
        } catch (Throwable e) {
            result = "error";
            log.info("【环绕增强中的--->异常增强】:the method 【" + methodName + "】 occurs exception " + e);
        }
        log.info("【环绕增强中的--->后置增强】:-----------------end.----------------------");
        return;
    }
}

第四步:在启动类上加上@EnableAspectJAutoProxy,开启Aspect注解

第五步:测试

/**
 * @Auther: Administrator
 * @Date: 2020/2/11 0011 21:31
 * @Description:
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {App.class})
public class TestAspect {

    @Autowired
    private UserService userService;


    @Test
    public void testSelectById(){
        User user = userService.selectById(2);
        System.out.println(user);
    }

}

执行结果:

0211 213816.079- INFO[           main] com.pian.aspect.MyAspect                -29: 【环绕增强中的--->前置增强】:the method 【selectById】 begins with [2]
0211 213816.112- INFO[           main] com.zaxxer.hikari.HikariDataSource      -110: HikariPool-1 - Starting...
0211 213816.117- WARN[           main] com.zaxxer.hikari.util.DriverDataSource -68: Registered driver with driverClassName=oracle.jdbc.driver.OracleDriver was not found, trying direct instantiation.
0211 213816.347- INFO[           main] com.zaxxer.hikari.pool.PoolBase         -516: HikariPool-1 - Driver does not support get/set network timeout for connections. (oracle.jdbc.driver.T4CConnection.getNetworkTimeout()I)
0211 213816.352- INFO[           main] com.zaxxer.hikari.HikariDataSource      -123: HikariPool-1 - Start completed.
0211 213816.544- INFO[           main] com.pian.aspect.MyAspect                -32: 【环绕增强中的--->返回增强】:the method 【selectById】 ends with User(userid=2, userName=老虎, pwd=null, age=10, sex=女, birthday=Sun Feb 09 21:26:23 CST 2020)
0211 213816.545- INFO[           main] com.pian.aspect.MyAspect                -37: 【环绕增强中的--->后置增强】:-----------------end.----------------------

完美:这样我们就可以在发起请求时记录开始,请求返回后记录日志,这样方便以后定位问题。希望能帮助到大家

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值