前置条件
其实考虑这个问题的时候必须知道springaop 中存在2中代理,一个是jdk代理,一个cglib代理,并且这两者是有区别的,首先知道的一点,jdk代理是目标对象实现接口,也就是说jdk代码是基于接口的方式
同样一个问题:jdk代理,目标对象能继承一个父类,而不实现接口吗?为什么?
jdk代理生成代理对象
这里我们编写一生成的代码片段如下截图
public class Test {
public static void main(String[] args) throws IOException {
byte[] wfgClasses = ProxyGenerator.generateProxyClass("wfgClass", new Class[]{UserDao.class});
File wfgClasses1 = new File("/Users/wufagang/wfgClass.class");
System.out.println(wfgClasses1.getPath());
OutputStream out = new FileOutputStream(wfgClasses1);
out.write(wfgClasses);
out.flush();
out.close();
}
}
生成的代理对象的class文件如下
public final class wfgClass extends Proxy implements UserDao {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public wfgClass(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 void saveUser() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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 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"));
m3 = Class.forName("com.wfg.aop2.UserDao").getMethod("saveUser");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
总结: public final class wfgClass extends Proxy implements UserDao {
由此可以看到生成的代理对象继承Proxy类,实现我们定义的接口,java语言又是单继承的,所以jdk代理必须是实现接口不能是继承类
aop中this和target的区别
this表示代理对象
target表示目标对象
4.this JDK代理时,指向接口和代理类proxy,cglib代理时 指向接口和子类(不使用proxy)
5.target 指向接口和子类
此处需要注意的是,如果配置设置proxyTargetClass=false,或默认为false,则是用JDK代理,否则使用的是CGLIB代理
- JDK代理的实现方式是基于接口实现,代理类继承Proxy,实现接口。
-
- 而CGLIB继承被代理的类来实现。
- 所以使用target会保证目标不变,关联对象不会受到这个设置的影响。
- 但是使用this对象时,会根据该选项的设置,判断是否能找到对象。
@Pointcut(“target(com.chenss.dao.IndexDaoImpl)”)
//目标对象,也就是被代理的对象。限制目标对象为com.chenss.dao.IndexDaoImpl类@Pointcut(“this(com.chenss.dao.IndexDaoImpl)”)
//当前对象,也就是代理对象,代理对象时通过代理目标对象的方式获取新的对象,与原值并非一个
这个比较难…proxy模式里面有两个重要的术语proxy Classtarget
ClassCGLIB和JDK有区别 JDK是基于接口 cglib是基于继承所有this可以在cglib作用
代码演示
这几天学习这一块我们应该可以很快写出来下面的代码没有难点
package com.wfg.aop2.dao;
/**
* @author wufagang
* @description
* @date 2021年04月24日 3:03 下午
*/
public interface IndexDao {
public void saveUser(String user);
}
package com.wfg.aop2.dao;
import org.springframework.stereotype.Service;
/**
* @author wufagang
* @description
* @date 2021年04月24日 3:03 下午
*/
@Service
public class IndexDaoImpl implements IndexDao {
@Override
public void saveUser(String user) {
System.out.println("save user" + user);
}
}
package com.wfg.aop2;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* @author wufagang
* @description
* @date 2021年04月24日 3:08 下午
*/
@Configuration
@ComponentScan("com.wfg.aop2")
@EnableAspectJAutoProxy(proxyTargetClass=false)
public class AppConfig {
}
package com.wfg.aop2;
import com.wfg.aop2.dao.IndexDao;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* @author wufagang
* @description
* @date 2021年04月24日 3:06 下午
*/
@Aspect
@Component
public class IndexAspect {
@Before("this(com.wfg.aop2.dao.IndexDaoImpl)")
public void before(){
System.out.println("before==============");
}
@After("target(com.wfg.aop2.dao.IndexDaoImpl)")
public void after(){
System.out.println("after==============");
}
}
package com.wfg.aop2;
import com.wfg.aop2.dao.IndexDao;
import com.wfg.aop2.dao.IndexDaoImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.lang.reflect.Proxy;
/**
* @author wufagang
* @description
* @date 2021年04月24日 3:09 下午
*/
public class Test2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
IndexDao bean = context.getBean(IndexDao.class);
System.out.println("类名称:"+bean.getClass().getName());
System.out.println("bean instanceof IndexDao :"+(bean instanceof IndexDao));
System.out.println("bean instanceof IndexDaoImpl :"+(bean instanceof IndexDaoImpl));
System.out.println("bean instanceof Proxy :"+(bean instanceof Proxy));
bean.saveUser("zhangsan");
}
}
代码测试:
@EnableAspectJAutoProxy(proxyTargetClass=false)
@EnableAspectJAutoProxy(proxyTargetClass=true)
通过上面的结果总结可知:
项目 | this是否命中 | target是否命中 | 是否属于Dao | 是否属于Impl | 是否属于Proxy |
---|---|---|---|---|---|
jdk代理 | 未 | 命中 | 是 | 否 | 是 |
cglib代理 | 命中 | 命中 | 是 | 是 | 否 |
深思:
@Before(“this(com.wfg.aop2.dao.IndexDaoImpl)”)我们将这个修改成
@Before(“this(com.wfg.aop2.dao.IndexDao)”) 此时不久可以命中了吗? java本身就是面向接口编程,但是this和target还有其他的区别吗?
目前我理解的修改成@Before(“this(com.wfg.aop2.dao.IndexDao)”)就没啥差别了,验证效果也是一样的。。。
更多的知识后面我们看源码的时候再说吧