java完结--springAOP源码解析----3

自定义注解:

   xml是干嘛的:用来描述元数据的

   例:user类和user表关联起来,用文本文件关联起来的。

   自定义注解:

代码1:luban/aop1:

复刻代码:

代码讲解:

package com.luban.aop.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//TYPE表示是出现在类上的,不能应用在属性上 FIELD表示属性......
//@Target(ElementType.TYPE)
@Target({ElementType.TYPE,ElementType.FIELD})
//表示仅仅存在源代码 编译为class没有了
//@Retention(RetentionPolicy.SOURCE)
//这个才能在执行的时候被发掘到
@Retention(RetentionPolicy.RUNTIME)
public @interface Entity {
    //value是在@Entity可以不指定其余的要指定 @Entity(value="city")
    public String value();
}

 

@Entity(value="city")
public class CityEntity {
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String id;
    private String name;

}

 

public class CommonUtil {
    public static String builfQueryEntity(Object object) {
        Class clazz = object.getClass();
        //判断是否加了注解
        Entity entity = null;
        if(clazz.isAnnotationPresent(Entity.class)){
            //得到注解的值
            entity = (Entity)clazz.getDeclaredAnnotation(Entity.class);
            System.out.println(entity.value());
        }
        String sql = "select * from ";

        return sql+entity.value();
    }
}

和springboot的@Value有异曲同工之处。

--------------------------------------------------------------------------------------------------------------------------------------------------------------

AOP

------------------------

aop:002538

代码2:luban/aop2aop

aop文档

看这个博客:https://blog.csdn.net/qq_28764557/article/details/100189201

这个章节讲的是aop的知识。

---------------------------------------------------------------

解决横切性的问题:不会影响我们的主业务逻辑。

Aspect:切面就是以下所有功能的集合,是一个载体是一个概念,可能是类ASPECTJ,XML就是个标签。

Join point:连接点目标对象中的方法。

pointcut:切点,连接点的集合。

Target object:目标对象,切入之前的对象。

AOP proxy:代理对象,切入之后的对象,就是增强之后的对象。

Wearing:织入,方法变为代理方法的过程。

Introduction:

Advice:通知,织入的代码放入的位置,通知的具体的内容。

 AspectJ。

 

Spring实现AOP 。

aspect实现AOP。

默认是使用JDK的动态代理。

为什么两个?spring借助了ASPECTJ的语法。

体现就是借助了一个注解。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

aop是解决横切性的问题,不影响主业务。

两种方法:

代码2:luban/aop2aop

声明一个aop步骤:

1.引入@EnableAspectJAutoProxy在配置文件或者xml来开启aop

2.加pom依赖

3.加@Aspect 切面

4.加@pointCut 切点可以关联多个和连接点

5.通知@Before

package com.luban.appconfig;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    
}

很简单就开启了aop的支持。这格式必须要开启的。

aop的中文文档:https://www.docs4dev.com/docs/zh/spring-framework/4.3.21.RELEASE/reference/aop.html#aop-introduction-defn

写aop:

 Aspect要单独引用的。

  <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.0</version>
    </dependency>

spring借助了AspectJ的语法的。

举例:

如何声明切点:

 //切点在哪里就是在dao下面的任意包的任意子包下面的方法
    @Pointcut("execution(* com.luban.dao.*.*(..))")
    public void pointCut(){

    }

 

如何声明通知:

@Before("pointCut()")
    public void before() {
        System.out.println("before通知");
    }

调用方法的时候才引起aop。

代码:

------------------------------------------------------------------------------------------------------------------------------------------------------------

这个是很重要的:

上面的是切点的声明支持的表达式:

execution和within的区别:面试问题

代码2:

@Component
@Aspect
public class Aspect1 {


    @Pointcut("within(com.luban.dao.*)")
    public void pointCutWithWithis() {

    }

    @Before("pointCutWithWithis()")
    public void before() {
        System.out.println("before通知within");
    }
}

跑下依然可以的。

举例:代码:

  @Pointcut("execution(public String com.luban.dao.*.*(..))")
    public void pointCut() {

    }

excusion定义到方法:可以定义到最小的粒度

* * com.luban.dao.*.*(..)

*:方法的类型

*:方法返回值类型,方法是目标方法

*:方法放入可见性

*:方法名字

..:参数类型 注意有顺序性质的

within:粒度为类

定义到类。

--------------------------------------------------------------------------------------------------

代码:

args的用法,定义到参数:

@Pointcut("args(java.lang.String)")
    public void pointArgs(){

    }
 @Before("pointCutWithWithis()&&!pointArgs()")
    public void before(){
        System.out.println("before");
    }

目前这三个已经有了结果:

------------------------------------------------------------------------------------------------------------

自定义一个注解:看代码即可。

自定义一个注解:

@Retention(RetentionPolicy.RUNTIME)
public @interface Luban {

}
@Retention(RetentionPolicy.RUNTIME)
public @interface Luban {

}
 @Luban
    public void qyeryLuban(String a){
        System.out.println("dao1");
    }

 

在这里加了注解才可以的。

@Luban
public void qyeryLuban(String a){
    System.out.println("dao1");
}

-------------------------------------------------------------------------------------------------------------------------------------------------

关键的关键重点:

复刻代码:

两个源码this和@target

-------------------------------------------

实验的代码和现象:

代码:

@Configuration
//false是JDK的
//@EnableAspectJAutoProxy(proxyTargetClass =  false)
@EnableAspectJAutoProxy(proxyTargetClass =  false)
//@ComponentScan(value="com.luba.dao2")
@ComponentScan({"com.luban"})
public class AppConfig {

}
 public static void main(String[] args) {
        AnnotationConfigApplicationContext  annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
//        IndexDao dao = annotationConfigApplicationContext.getBean(IndexDao.class);
        Dao dao = (Dao)annotationConfigApplicationContext.getBean("indexDao");
        System.out.println(dao instanceof IndexDao);
        dao.qyery(1);
    }

此时打印为false

@Configuration
//false是JDK的
//@EnableAspectJAutoProxy(proxyTargetClass =  false)
@EnableAspectJAutoProxy(proxyTargetClass =  true)
//@ComponentScan(value="com.luba.dao2")
@ComponentScan({"com.luban"})
public class AppConfig {

}

此时打印为true

----------------------------------------------------------------------------------------------------------

  建一个接口:Dao 

改下方式:

注意此时不是一个对象了,为false。

在容器中没有IndexDao:是因为什么呢?因为代理对象不是IndexDao了

加这个就不报错了。

并且打印为true。

true是用的cglib  其他的用的是JDK动态代理。

为什么?aop写了满足推荐了要是JDK的动态代理的话或者其他的就变为代理对象了。而不是调用才变的。

看文档:

JDK动态代理为什么一定要用接口而不是继承?

实现代理:继承 聚合 动态代理

JSK是聚合。

--------------------------------------------------------------------------------------------------------------------------------------------------------

代码:

写一个动态代理的例子:

   /**
         * 还原JDK动态代理产生的字节码
         */
        Class<?>[] interfaces = new Class[]{Dao.class};
        byte bytes[] = ProxyGenerator.generateProxyClass("lubanAa",interfaces);
        File file = new File("d:\\Test.class");
        try{
            FileOutputStream fw = new FileOutputStream(file);
            fw.write(bytes);
            fw.flush();
            fw.close();
          }catch(Exception e){
            e.printStackTrace();
           }
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.luban.dao.Dao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class lubanAa extends Proxy implements Dao {
    private static Method m1;
    private static Method m2;
    private static Method m4;
    private static Method m3;
    private static Method m0;

    public lubanAa(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void qyery1(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});//h是生成出来的代理对象是基于接口的
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void qyery() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.luban.dao.Dao").getMethod("qyery1", Class.forName("java.lang.String"));
            m3 = Class.forName("com.luban.dao.Dao").getMethod("qyery");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

h是innoveationhandler接口。

JDK动态代理为什么只能是基于接口:因为是单继承的

已经继承了Proxy了。

所以看,它既是Dao也是Proxy就是不等于我们的目标对象。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

JDK的话代理对象不是原来的对象了,接口是一个。

注意看里面根本没有IndexDao了,已经被代理了。

------------------------------------------------------------------------------------------------------------------------------------------------------------------

cglib是继承了目标对象----------------------------------------------------------------------------

 

-----

总结:this是加在代理上对象,target是加在了目标对象。

---

 

 //this是代理对象
    @Pointcut("this(com.luban.dao.IndexDao)")
    public void pointCutThis(){

    }

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

这样写的话true是增强,false不是增强。fasle是动态代理。

之所以不增强是因为dao不是代理对象,代理对象继承了Proxy。

增强是因为dao是被代理对象继承的对象。

this是匹配的代理对象。

代码:

@Configuration
//false是JDK的
//@EnableAspectJAutoProxy(proxyTargetClass =  false)
@EnableAspectJAutoProxy(proxyTargetClass =  true)
//@ComponentScan(value="com.luba.dao2")
@ComponentScan({"com.luban"})
public class AppConfig {

}

target永远可以的。

-----

------------------------------------------------------

 

------------------------------------------

石墨文档:https://shimo.im/docs/Nj0bcFUy3SYyYnbI/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值