Spring AOP的实现

7 篇文章 0 订阅

Spring AOP的实现

Aspectj增强

aop类

@Aspect
@Component
public class AopSerivce {
    @Before("execution(* com.example.springtest.UserService.login())")
    public void befor(){
        System.out.println("登入日志");
    }
}

业务类

@Service
@Component
public class UserService {
    public void login(){
        System.out.println("登入成功");
    }
}

Springboot启动类

@SpringBootApplication
public class SpringtestApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringtestApplication.class, args);
        UserService bean = context.getBean(UserService.class);
        bean.login();
        context.close();

    }
}

控制台输出

2022-04-11 12:08:15.799  INFO 2468 --- [           main] c.e.springtest.SpringtestApplication     : Starting SpringtestApplication using Java 1.8.0_65 on DESKTOP-K588PHT with PID 2468 (D:\JavaDemo\springtest\target\classes started by Jack Yang in D:\JavaDemo\springtest)
2022-04-11 12:08:15.801  INFO 2468 --- [           main] c.e.springtest.SpringtestApplication     : No active profile set, falling back to 1 default profile: "default"
2022-04-11 12:08:16.256  INFO 2468 --- [           main] c.e.springtest.SpringtestApplication     : Started SpringtestApplication in 0.717 seconds (JVM running for 1.686)
登入日志
登入成功

我们发现完成了aop实现

AJC增强是改写了class实现的增强,因为它改写了class文件所有没有进行代理,因为改写了class所有也不依靠spring容器

使用这种Aspectj增强的好处就是可以突破代理的限制,比如方法是一个静态方法,用代理就不能增强,而Aspectj就可以增强

Aspectj就是把编译好的类进行一个增强

注意: 如果idea调用了java的编译器,那么就不会实现aop功能,必须调用aspectj的编译器才可以(在pom文件的build引用aspectj编译器)。

Agent增强

​ agent是在类加载过程的时候实现增强,

​ 运行的时候需要在VM options里引入 -javaagent:${maven仓库地址}/org/aspectj/aspectjweaver/1.9.7/aspectjwaver-1.9.7.jar

proxy增强

jdk动态代理(java自带的代理功能)

jdk动态代理有一个限制,只能针对接口代理

基于JDK实现的代理可以允许目标为final的类型

jdk代理与目标类的关系是平级关系

jdk一个方法对应一个代理

public class Jdkproxy {
    interface Foo{
        void foo();
    }

    static class Target implements Foo{
        @Override
        public void foo() {
            System.out.println("巴啦啦能量");
        }
    }

    public static void main(String[] args) {
        Target target = new Target();
        ClassLoader loder = Jdkproxy.class.getClassLoader();    //用来在加载过程期间动态生成的字节码
        /**
         * loder                  加载过程中动态生命的字节码
         * new Class[]{Foo.class} 代理类要实现的哪些接口
         *  new InvocationHandler().... 执行代理类要执行的行为
         */
        Foo before = (Foo) Proxy.newProxyInstance(loder, new Class[]{Foo.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("before");
                Target invoke = (Target) method.invoke(target, args);
                System.out.println("after");
                return invoke;      //让代理也返回目标方法执行的结果
            }
        });

        before.foo();
    }
}
jdk方法反射的优化

​ jdk调用16次,第17次的时候他会针对一个方法会产生一个代理类,这个代理类能让反射变成无需反射,

cglib(第三方的代理技术)

cglib不像jdk代理一样有限制,它可以针对针对接口,如果目标没有实现任何接口也可以

cglib与类的关系是子父关系,代理是子类型,目标是父类型,不能根据final生成,只要是子父级关系肯定是通过重写来实现的代码增强

cglib一个代理类会对应2个FastClass,一个fastclass配合目标一起调用,另一个fastclass配合代理本身一起调用的,一个fastclas对应多个方法

public class Jdkproxy {


    static class Target  {
        public void foo() {
            System.out.println("巴啦啦能量");
        }
    }

    public static void main(String[] a) {
     Target target = new Target();
        Target o1 = (Target) Enhancer.create(Target.class, (MethodInterceptor) (o, method, args, methodProxy) -> {
            System.out.println("brfore");
            Target invoke = (Target) method.invoke(target, args);   //用方法反射调用目标
            //methodProxy避免反射调用方法
            methodProxy.invoke(target, args);     //需要目标,内部类没有反射
            methodProxy.invokeSuper(target,args);//内部类没有反射,需要代理
            System.out.println("after");
            return invoke;
        });
        o1.foo();
    }
}

Spring用的是 methodProxy.invoke(target, args);

我们代理类去调用目标有3种方法,

1.用方法反射区调用目标

2.invoke是配合目标使用的(Spring是用的这个)

3.invokeSuper是配合代理使用的

cglib的反射优化

​ 第一次就产生代理,就无需反射

Spring选择代理

Spring选择代理技术的规则

​ 情况A:proxyTargerClass = false ,目标实现了接口,用jdk实现

​ 情况B:proxyTargerClass = false , 目标没有实现接口,用cglib实现(因为jdk必须要目标有实现接口)

​ 请假C:proxyTargerClass = true , 总是使用cglib实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哇塞大嘴好帅(DaZuiZui)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值