使用AOP进行编程笔记

在这里我们使用的是springboot框架,需要加入AOP的依赖;

如下:

<!-- 使用切面编程-->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

然后我们编写一个切面类;

@Component
@Aspect
public class ValidUserNameAspect {
    

	//切入点(这个切点是针对于注解的)
	@Pointcut("@annotation(com.jeecms.annotation.ValidUserName)")
	public void validUserName() {
	
	}
	//切入点(这个切点需要使用execution表达式了)
	@Pointcut(value = "execution(* com.jeecms.controller.*.*(..))")
    public void excServerPonit() {
    }
	
	//使用场景
    @Before(value="@annotation(validUserName)")
	public Object ValidUser(JoinPoint joinPoint,ValidUserName validUserName) {
		
		//获取方法上的所有参数
		Object[] arguments = joinPoint.getArgs();
		    
		for (Object object : arguments) {
            System.out.println(object);
        }		
		String value = validUserName.value();
		System.out.println(value);	
		return true;		
	}
}

然后讲解一下

1.首先我们需要将这个类加上@Aspect这个注解,表示这是一个切面类,@Component这个注解也是必须的,把普通pojo实例化到spring容器中

2.定义切点需要用到@Pointcut,这里说明一下Execution切点函数

这里这篇写的蛮好的,可以看看这个,链接:https://blog.csdn.net/yangshangwei/article/details/77627825

这个讲切点函数比较详细;

https://blog.csdn.net/autfish/article/details/51184405,这篇有讲到更多的切点函数以及逻辑运算,也很好;

重点:参数部分允许使用通配符:

*  匹配任意字符,但只能匹配一个元素

.. 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用

+  必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类

3.@Before这个注解就是切面的通知注解,表示在执行方法之前,叫前置通知,还有其他的通知如下:

@After: 后置通知, 在方法执行之后执行 。

@AfterRunning: 返回通知, 在方法返回结果之后执行

@AfterThrowing: 异常通知, 在方法抛出异常之后

@Around: 环绕通知, 围绕着方法执行,环绕通知方法可以包含上面四种通知方法,环绕通知的功能最全面。环绕通知需要携带 ProceedingJoinPoint 类型的参数,且环绕通知必须有返回值, 返回值即为目标方法的返回值。在切面类中创建环绕通知方法

具体可以看如下链接:

https://blog.csdn.net/u010502101/article/details/78823056

4.关于AOP的原理

可以查看这篇文章:https://juejin.im/post/591d8c8ba22b9d00585007dd,也是自己照着撸的,有更深的体会;

讲到了代理模式,

静态代理:静态代理产生于代码编译阶段,编译完成后就不能修改了,Iperson就是一个接口,Person类实现了这个接口

我们在创建PersonProxy这个类的时候把person注入构造函数,就能通过这个代理获取到Person类的方法了;

package com.jeecms.proxy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 使用静态代理类(局限性:需要固定的类编写接口(或许还可以接受,毕竟有提倡面向接口编程),需要实现接口的每一个函数(不可接受),同样会造成代码的大量重复,将会使代码更加混乱。)
 * @author jinlei
 *
 */
public class PersonProxy {

    private Iperson iPerson;
    private final static Logger logger = LoggerFactory.getLogger(PersonProxy.class);

    public PersonProxy(Iperson iPerson) {
        this.iPerson = iPerson;
    }
    public void doSomething() {
        logger.info("Before Proxy");
        iPerson.doSomething();
        logger.info("After Proxy");
    }

    public static void main(String[] args) {
        PersonProxy personProxy = new PersonProxy(new Person());
        personProxy.doSomething();
    }

}

 

jdk自带的动态代理模式可以看看这个:https://blog.csdn.net/lovejj1994/article/details/78080124

package com.jeecms.proxy;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * JDK自带的动态代理
 * 使用Java反射机制,它的好处理时可以为我们生成任何一个接口的代理类,并将需要增强的方法织入到任意目标函数。
 * 但它仍然具有一个局限性,就是只有实现了接口的类,才能为其实现代理。
 * @author jinlei
 *
 */
public class PersonProxyjdk implements InvocationHandler{

    private Object obj;
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public Object bind(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        Object result = null;
        try {
            logger.info("Before Proxy");
            result = method.invoke(obj, args);
            logger.info("After Proxy");
        } catch (Exception e) {
            throw e;
        }
        return result;

    }

    public static void main(String[] args) {
        PersonProxyjdk personProxy = new PersonProxyjdk();
        Iperson iperson = (Iperson) personProxy.bind(new Person());
        iperson.getSomething();
        iperson.doSomething();
    }

}

cglib动态代理模式可以看看这个:https://blog.csdn.net/Q_AN1314/article/details/79724334

package com.jeecms.proxy;

import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
 * CGLIB解决了动态代理的难题,它通过生成目标类子类的方式来实现来实现代理,而不是接口,规避了接口的局限性。
 * CGLIB是一个强大的高性能代码生成包(生成原理还没研究过),其在运行时期(非编译时期)生成被 代理对象的子类,并重写了被代理对象的所有方法,从而作为代理对象。
当然CGLIB也具有局限性,对于无法生成子类的类(final类),肯定是没有办法生成代理子类的
 * @author jinlei
 *
 */
public class PersonProxycglib implements MethodInterceptor{

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        logger.info("Before Proxy");
        Object result = methodProxy.invokeSuper(proxy, args);
        logger.info("After Proxy");
        return result;
    }
    public static Person getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Person.class);

        enhancer.setCallback(new PersonProxycglib());
        return (Person) enhancer.create();
    }
    
    public static void main(String[] args) {
        PersonProxycglib sf = new PersonProxycglib();
        Person sd = sf.getProxyInstance();
        sd.getSomething();
    }
}

记录下来,防止遗忘。如果能帮到各位,那就更好了

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值