System.out.println(“收中介费”);
}
@Override
public void rentHouse() {
seeHouse();
host.rentHouse();
fare();
}
}
4)客户成功租到房子,并且不经过房东
public class Client {
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy();
proxy.setHost(host);
proxy.rentHouse();
}
}
在实际的开发过程中,往往前人已经将基本的框架已经搭建完成,这个时候,我们要做的不应该是在原有代码上修改,而是在不改变原来的代码的情况下,实现了对原有功能的增强,这也是 面向切面编程(AOP)中最核心的思想。
案例: 原有项目中已经存在增删改查业务,现在想要在基础业务上增加日志业务。
代码实现:
思路一:在原有实现类上增加代码
public class BaseServiceImp implements BaseService {
@Override
public void add() {
// 需要在每个业务方法上都增加一个日志方法
// 这样便破坏了源代码的结构,这在实际开发中是大忌
System.out.println(“提供了增加功能的日志”);
System.out.println(“实现了增加功能”);
}
@Override
public void delete() {
System.out.println(“提供了删除功能的日志”);
System.out.println(“实现了删除功能”);
}
@Override
public void update() {
System.out.println(“提供了更改功能的日志”);
System.out.println(“实现了更改功能”);
}
@Override
public void query() {
System.out.println(“提供了查询功能的日志”);
System.out.println(“实现了查询功能”);
}
}
思路二:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的
1)原有的 Service 实现类
/**
- 保持原有业务不变
*/
public class BaseServiceImp implements BaseService {
@Override
public void add() {
System.out.println(“实现了增加功能”);
}
@Override
public void delete() {
System.out.println(“实现了删除功能”);
}
@Override
public void update() {
System.out.println(“实现了更改功能”);
}
@Override
public void query() {
System.out.println(“实现了查询功能”);
}
}
2 )加入代理类
public class BaseServiceProxy implements BaseService {
private BaseServiceImp service;
public BaseServiceImp getService() {
return service;
}
public void setService(BaseServiceImp service) {
this.service = service;
}
@Override
public void add() {
log(“add”);
service.add();
}
@Override
public void delete() {
log(“delete”);
service.delete();
}
@Override
public void update() {
log(“update”);
service.update();
}
@Override
public void query() {
log(“query”);
service.query();
}
public void log(String msg){
System.out.println(“执行了”+msg+“方法”);
}
}
3)客户测试类
public class Client {
public static void main(String[] args) {
BaseServiceImp service = new BaseServiceImp();
BaseServiceProxy proxy = new BaseServiceProxy();
// 这样的话,不修改原有的 BaseService 业务就可以实现日志的方法
proxy.setService(service);
// 现在利用代理的方式
proxy.add();
proxy.delete();
proxy.update();
proxy.query();
// 原有的方式
// service.add();
// service.delete();
// service.update();
// service.query();
}
}
=========================================================================
静态代理有一个缺点,就是每次代理一个角色,代码量都会翻倍。而动态代理解决了这个问题。
动态代理的底层都是反射。动态代理可以有很多种实现方式,比如:基于接口的动态代理、基于类的动态代理、基于 Java 字节码的动态代理。
下面详细介绍一下基于接口的动态代理,即基于 JDK (原生类)的动态代理。该方法的核心是两个,一个是 Proxy 类,另一个是 InvocationHandler 接口。
接下来用动态代理的方式来修改之前静态代理的代码。
1)待实现的接口类
public interface Rent {
public void rent();
}
2)原有的实现类
public class Host implements Rent {
@Override
public void rent() {
System.out.println(“我是房东,我想要出租房子。”);
}
}
3)加入的代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
// 1 代理谁:被代理的接口
private Rent rent;
public void setRent(Rent rent){
this.rent = rent;
}
/**
-
2 生成代理类,重点是第二个参数,获取要代理的抽象角色
-
@return 生成代理类
*/
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
/**
- 3 处理代理实例的方法调用并返回结果
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
// 关键的一步,本质使用反射来实现
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println(“带房客看房”);
}
//收中介
【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 开源分享
费
public void fare(){
System.out.println(“收中介费”);
}
}
4)测试
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();
}
}
3)加入的代理类
可以当成一个工具类。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
// 被代理的接口
private Object target;
public void setTarget(Object target){
this.target = target;
}
// 生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),