一、静态代理
可以用现实生活中的例子来说,房东有房子要出售,但是不可能一下子就找到客户,此时可以交给代理去做,那么代理就会和房东一样具有租房的权利,但是代理就不一定只会去租房,还会收取中介费等,而客户最后也可以通过代理实现租房。
放到程序中,可以认为是代理实现的不仅仅是帮房东租房的业务,还可以实现其他的功能,这样就可以扩充具体实现类的功能!!
通过上图,可以得到四个角色:客户、代理角色、真实角色、抽象接口
接口:租房
public interface Rent {
public void rent();
}
房东 : 真实的角色
public class Host implements Rent{
public void rent() {
System.out.println("房东出租房子");
}
}
代理角色:中介
//中介代理 帮房东租房
public class Agent implements Rent {
//拿房东
private Host host;
public Agent(Host host){
this.host=host;
}
public void rent() {
look();
host.rent();
fee();
}
public void look(){
System.out.println("带客户看房");
}
public void fee(){
System.out.println("收取中介费");
}
}
client:客户
public class Client {
public static void main(String[] args) {
Agent agent = new Agent(new Host());
agent.rent();
}
}
二、动态代理
- 动态代理和静态代理角色一样,动态代理是直接生成的,不是直接写的。
Spring AOP中的动态代理主要有两种方式:JDK动态代理和CGLIB动态代理
JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。现在都推荐面向接口编程,我们做的项目都是各种接口+实现类,所以是不是觉得这种代理方式和现在的接口编程很符合呢!
下面我们延续上面的例子进行说明,上面的静态代理对象是我们写出来的,而动态代理可以生成!!
完整代码
房东 真实的角色
public class Host implements Rent{
public void rent() {
System.out.println("房东出租房子");
}
}
Rent 接口
public interface Rent {
public void rent();
}
自动生成代理类
package com.zhoudan.demo2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//可以自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
//处理代理实例 返回结果 可以理解为得到调用方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
Object result = method.invoke(rent, args);
fee();
return result;
}
public void seeHouse(){
System.out.println("中介带着看房子");
}
public void fee(){
System.out.println("中介收取中介费");
}
}
client
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//处理接口对象
pih.setRent(host);
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
三、AOP
与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象(我们可以把它称之为‘代理对象’),这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
-
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
-
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
-
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
-
目标(Target):被通知对象。
-
代理(Proxy):向目标对象应用通知之后创建的对象。
-
切入点(PointCut):切面通知 执行的 “地点”的定义。
-
连接点(JointPoint):与切入点匹配的执行点。
使用aop时要先导入依赖和在xml中进行相应的配置和约束:
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
定义一个接口和一个实现类:
有以下三种实现方式:
方式一:
先定义两个类,分别执行前置通知和后置通知
方式二:使用自定义的类作为切入面
方式三:使用注解
由于笔者能力有限,对aop的理解还不够透彻。如果有错误的地方,大家可以多多指出,我们共同进步!!