动态代理
一、CGLIB动态代理
1、原理:利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理,CGLIB 通过动态生成一个需要被代理类的子类(即被代理类作为父类),该子类重写被代理类的所有不是 final 修饰的方法,并在子类中采用方法拦截的技术拦截父类所有的方法调用,进而织入横切逻辑。
package com.onlymark.proxy;
import com.onlymark.service.UserService;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @auther Onlymark
* @date 2021/5/7 上午6:05
*/
public class JavaProxyFactory1 implements MethodInterceptor {
private UserService userService;
public JavaProxyFactory1(UserService userService) {
this.userService = userService;
}
//cglib
public UserService createUserServiceProxy(){
Enhancer enhancer = new Enhancer();
//设置Enhancer对象的父类
enhancer.setSuperclass(UserService.class);
//设置回调方法
enhancer.setCallback(this);
//创建代理对象
UserService service = (UserService)enhancer.create();
//返回代理对象
return service;
}
/**
* obj:cglib生成的代理对象 obj表示增强的对象,即实现这个接口类的一个对象;
* method:被代理对象方法 method表示要被拦截的方法;
* args:方法入参 args表示要被拦截方法的参数;
* methodProxy: 代理方法 proxy表示要触发父类的方法对象;
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务");
Object object = method.invoke(userService, args);
System.out.println("关闭事务");
return object;
}
public static void main(String[] args) {
JavaProxyFactory1 javaProxyFactory1 = new JavaProxyFactory1(new UserService());
UserService userServiceProxy = javaProxyFactory1.createUserServiceProxy();
userServiceProxy.adduser();
userServiceProxy.deleteuser();
}
}
一、动态代理
1.增强方法增强方法
package cn.tt.trendsProxy.JDKproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author Tzc
* 这个类可以(自动生成代理类)
* 实现方式:
* 1. 静态代理:有一个类文件描述代理模式
* 2. 动态代理:在内存中形成代理类
* * 实现步骤:
* 1. 代理对象和真实对象实现相同的接口
* 2. 代理对象 = Proxy.newProxyInstance();
* 3. 使用代理对象调用方法。
* 4. 增强方法
*
* * 增强方式:
* 1. 增强参数列表
* 2. 增强返回值类型
* 3. 增强方法体执行逻辑
*/
@SuppressWarnings("all")
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//实现接口(抽象角色)生成得到代理类(处理程序方法生成我们要调用的接口对象)
/* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
newProxyInstance,方法有三个参数:
loader: 用哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接口
h:动态代理方法在执行时,会调用h里面的invoke方法去执行*/
/*
getClass()取得当前对象所属的Class对象,通过getClass()方法得到该对象类Class后,可以通过Class获取这个类中的相关属性和方法
getClassLoader()取得该Class对象的类装载器类装载器负责从Java字符文件将字符流读入内存,并构造Class类对象
getClassLoader()把Class文件加载进内存封装为类对象
getInterfaces()方法和Java的反射机制有关。它能够获得这个对象所实现的所有接口。
三个参数:
1. 类加载器:真实对象.getClass().getClassLoader()
2. 接口数组:真实对象.getClass().getInterfaces()
3. 处理器:new InvocationHandler()
*/
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
/*
InvocationHandler 是代理实例的调用处理程序 实现的接口。
每个代理实例都具有一个关联的调用处理程序。
对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。
*/
/*
proxy - 在其上调用方法的代理实例
method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
参数:
1. proxy:代理对象
2. method:代理对象调用的方法,被封装为的对象
3. args:代理对象调用的方法时,传递的实际参数
*/
//执行生成的代理类的方法,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质就是使用反射机制实现
/* invoke方法参数:
obj - 从中调用底层方法的对象
args - 用于方法调用的参数
*/
Object result = method.invoke(rent, args);
//增强方法体执行逻辑
seeHouse();
hetong();
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("中介带我看房");
}
//签合同
public void hetong(){
System.out.println("签租赁合同");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
2.增强参数
package cn.itcast.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//1.创建真实对象
Lenovo lenovo = new Lenovo();
//2.动态代理增强lenovo对象
/*
三个参数:
1. 类加载器:真实对象.getClass().getClassLoader()
2. 接口数组:真实对象.getClass().getInterfaces()
3. 处理器:new InvocationHandler()
*/
SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
/*
代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
参数:
1. proxy:代理对象
2. method:代理对象调用的方法,被封装为的对象
3. args:代理对象调用的方法时,传递的实际参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*System.out.println("该方法执行了....");
System.out.println(method.getName());
System.out.println(args[0]);
*/
//判断是否是sale方法
if(method.getName().equals("sale")){
//1.增强参数
double money = (double) args[0];
money = money * 0.85;
System.out.println("专车接你....");
//使用真实对象调用该方法
String obj = (String) method.invoke(lenovo, money);
System.out.println("免费送货...");
//2.增强返回值
return obj+"_鼠标垫";
}else{
Object obj = method.invoke(lenovo, args);
return obj;
}
}
});
//3.调用方法
/* String computer = proxy_lenovo.sale(8000);
System.out.println(computer);*/
proxy_lenovo.show();
}
}
3.增强返回值
package cn.itcast.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
* 敏感词汇过滤器
*/
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.创建代理对象,增强getParameter方法
ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强getParameter方法
//判断是否是getParameter方法
if(method.getName().equals("getParameter")){
//增强返回值
//获取返回值
String value = (String) method.invoke(req,args);
if(value != null){
for (String str : list) {
if(value.contains(str)){
value = value.replaceAll(str,"***");
}
}
}
return value;
}
//判断方法名是否是 getParameterMap
//判断方法名是否是 getParameterValue
return method.invoke(req,args);
}
});
//2.放行
chain.doFilter(proxy_req, resp);
}
private List<String> list = new ArrayList<String>();//敏感词汇集合
public void init(FilterConfig config) throws ServletException {
try{
//1.获取文件真实路径
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
//2.读取文件
BufferedReader br = new BufferedReader(new FileReader(realPath));
//3.将文件的每一行数据添加到list中
String line = null;
while((line = br.readLine())!=null){
list.add(line);
}
br.close();
System.out.println(list);
}catch (Exception e){
e.printStackTrace();
}
}
public void destroy() {
}
}