Java高级特性之动态代理
学习之前首先介绍一下代理模式
这里拿手机销售来说、比方说三星厂商生产出了手机、之后需要经过销售、于是交给了厂商B来销售、所以B是一个代理销售商、但是厂商B在销售之前之后会做其他的动作。因此不仅仅是简单的进行销售。
流程图:
这里在模版上有点类似装饰者式,但是这里是不一样的。装饰者更强调行为、而代理模式更强调对象本身。
静态代理
1、被代理对象
/**
* @Author Zzneko
* @Date 2022/9/9 16:07
**/
public class ProxyObj {
public void sayHello(){
System.out.println("hello");
}
}
2、代理对象
package proxy.simpleProxy;
/**
* 代理对象
* */
public class Proxy {
private ProxyObj proxyObj;
public Proxy(ProxyObj proxyObj) {
this.proxyObj = proxyObj;
}
/**
* 代理方法
*/
public void methodEnhance(){
System.out.println("before say hello");
proxyObj.sayHello();
System.out.println("after say hello");
}
}
3、测试
/**
* @Author Zzneko
* @Date 2022/9/9 16:10
**/
public class ProgramEntering {
public static void main(String[] args) {
ProxyObj proxyObj = new ProxyObj();
Proxy proxy = new Proxy(proxyObj);
proxy.methodEnhance();
}
}
静态代理很简单这里就不做过多讲述了
动态代理
动态代理有两种
一、JDK
1、被代理的类。
package proxy.jdk;
/**
* @Author Zzneko
* @Date 2022/9/7 12:50
* 被代理类
**/
public class ServiceImp implements IService{
@Override
public void sayHello() {
System.out.println("hello");
}
@Override
public void fly() {
System.out.println("i am flying");
}
}
//-----------实现的接口
package proxy.jdk;
/**
* 代理接口
*/
public interface IService {
void sayHello();
void fly();
}
2、代理类
package proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @Author Zzneko
* @Date 2022/9/7 12:50
* 代理类
**/
public class SimpleInvocationHandler implements InvocationHandler {
//被代理的对象
private Object realObject;
public SimpleInvocationHandler(Object object) {
this.realObject = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("entering"+method.getName());
Object result = method.invoke(realObject, args);
System.out.println("leaving"+method.getName());
return result;
}
}
3、测试类
public class SimpleJDKDynamicProxyDemo {
public static void main(String[] args) {
IService service = new ServiceImp();
IService iService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(), new Class<?>[]{
IService.class
}, new SimpleInvocationHandler(service));
service.sayHello();
service.fly();
System.out.println("代理之后");
iService.fly();
iService.sayHello();
}
}
解读:
1、现在我们的创建的对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
这个方法创建、他拥有三个参数
1)loader标识类加载器
2)标识代理类要实现的接口列表,是一个数组,元素的接口类型只能是接口,不能是普通的类。
3)h的类型是InvocationHandler,它是一个接口,也定义在反射包中。它定义了一个方法inboke,对代理接口所有方法的调用都会转给该方法。
该方法返回的Object可以强制转换interfaces中的某个接口的类型。值得注意的是它不能强制换花为某个类类型。
二、CGLib
1、被代理对象
/**
* @Author Zzneko
* @Date 2022/9/7 13:18
**/
public class RealService {
public void sayHello(){
System.out.println("hello world");
}
}
2、代理对象
/**
* @Author Zzneko
* @Date 2022/9/7 13:18
**/
public class SimpleInterceptor implements MethodInterceptor {
//VM Jdk8之后 启动参数记得加上 --add-opens java.base/java.lang=ALL-UNNAMED
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("entering\t"+method.getName());
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("leaving\t"+method.getName());
return invoke;
}
public static<T> T getProxy(Class<T> cls){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(new SimpleInterceptor());
return (T) enhancer.create();
}
}
3、测试
/**
* @Author Zzneko
* @Date 2022/9/7 13:18
**/
public class SimpleCGLibDemo {
public static void main(String[] args) {
RealService realService = new RealService();
realService.sayHello();
System.out.println("代理类的方法");
RealService proxy = SimpleInterceptor.getProxy(RealService.class);
proxy.sayHello();
}
}
总结:
JDK中的代理面向的是一组接口、其背后不一定真正有被代理的对象,也可能有多个实际对象
cglib代理的是一个具体的类。他动态的创建类一个新类、继承该类、重写了其方法
动态代理应用-AOP
1、定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect{
Class<?>[] value();
}
2、定义切面类
/**
* @Author Zzneko
* @Date 2022/9/9 17:00
**/
@Aspect(ServiceB.class)
public class ExceptionAspect {
public static void exception(Object object,
Method method,
Object[] args,
Throwable e) {
System.err.println("exception when calling: " + method.getName()
+ "," + Arrays.toString(args));
}
}
package aop.Aspect;
import Annotaion.diInject.ServiceA;
import Annotaion.diInject.ServiceB;
import aop.annotaion.Aspect;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @Author Zzneko
* @Date 2022/9/9 17:00
**/
@Aspect({ServiceB.class, ServiceA.class})
public class ServiceLogAspect {
public static void before(Object object,
Method method,
Object[] args) {
System.out.println(
"entering " + method.getDeclaringClass().getSimpleName()
+ "::" + method.getName() + ", args: " + Arrays.toString(args)
);
}
public static void after(Object object,
Method method,
Object[] args,
Object result) {
System.out.println(
"leaving " + method.getDeclaringClass().getSimpleName()
+ "::" + method.getName() + ", result: " + result
);
}
}
3、定义容器
/**
* @Author Zzneko
* @Date 2022/9/9 17:04
**/
public class CGLibContainer {
/**
* 容器初始化分析所有带@Aspect的类,分析每个类的方法、前后需要调用那些方法。
* */
private static Map<Class<?>,Map<InterceptPoint, List<Method>>> interceptMethodsMap =new HashMap();
static Class<?>[] aspects = new Class<?>[] { ServiceLogAspect.class, ExceptionAspect.class };
static {
init();
}
private static void init(){
for (Class<?> cls : aspects) {
/**
* :用于获得切面的注解。
* 以及根据方法名、来获取方法。
* */
Aspect aspect = cls.getAnnotation(Aspect.class);
if (aspect!=null) {
Method before = getMethod(cls, "before", new Class<?>[]{ Object.class,
Method.class,
Object[].class
}
);
Method after = getMethod(cls, "after", new Class<?>[]{ Object.class,
Method.class,
Object[].class
}
);
Method exception = getMethod(cls,"exception",new Class<?>[]{Object.class,Method.class,Object[].class,Throwable.class});
//切面中面向的类。
Class<?>[] value = aspect.value();
for (Class<?> aClass : value) {
//对切面的对象生成代理类。
addInterceptMethod(aClass,InterceptPoint.BEFORE,before);
addInterceptMethod(aClass,InterceptPoint.AFTER,after);
addInterceptMethod(aClass,InterceptPoint.EXCEPTION,exception);
}
}
}
}
/***
* 添加被代理的类、以及被增强的方法。
* @param cls 被代理类。
* @param point 切点
* @param method 被代理方法
*/
private static void addInterceptMethod(Class<?> cls, InterceptPoint point, Method method) {
if (method==null) {
return;
}
/**
* 获得当前切面的所有方法
*/
Map<InterceptPoint, List<Method>> map = interceptMethodsMap.get(cls);
if (map==null) {
map=new HashMap<>();
interceptMethodsMap.put(cls,map);
}
List<Method> methods = map.get(point);
if (methods==null) {
methods=new ArrayList<>();
map.put(point,methods);
}
methods.add(method);
}
/**
* 创建代理类
* @param cls
* @param <T>
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
private static <T> T createInstance(Class<T> cls) throws InstantiationException, IllegalAccessException {
//如果容器有当前类对象、则直接返回否则进行代理创建。
if (!interceptMethodsMap.containsKey(cls)) {
return (T) cls.newInstance();
}
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(new AspectInterceptor());
return (T) enhancer.create();
}
/**
* 代理生成
*/
static class AspectInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
//执行before方法
List<Method> beforeMethods = getInterceptMethods(
object.getClass().getSuperclass(), InterceptPoint.BEFORE);
for (Method m : beforeMethods) {
m.invoke(null, new Object[] { object, method, args });
}
try {
// 调用原始方法
Object result = proxy.invokeSuper(object, args);
// 执行after方法
List<Method> afterMethods = getInterceptMethods(
object.getClass().getSuperclass(), InterceptPoint.AFTER);
for (Method m : afterMethods) {
m.invoke(null, new Object[] { object, method, args, result });
}
return result;
} catch (Throwable e) {
//执行exception方法
List<Method> exceptionMethods = getInterceptMethods(
object.getClass().getSuperclass(), InterceptPoint.EXCEPTION);
for (Method m : exceptionMethods) {
m.invoke(null, new Object[] { object, method, args, e });
}
throw e;
}
}
}
private static Method getMethod(Class<?> cls, String name, Class<?>[] paramTypes) {
try {
return cls.getMethod(name, paramTypes);
} catch (NoSuchMethodException e) {
return null;
}
}
static List<Method> getInterceptMethods(Class<?> cls, InterceptPoint point) {
Map<InterceptPoint, List<Method>> map = interceptMethodsMap.get(cls);
if (map == null) {
return Collections.emptyList();
}
List<Method> methods = map.get(point);
if (methods == null) {
return Collections.emptyList();
}
return methods;
}
/**
* 属性注入以及容器获取
* @param cls
* @param <T>
* @return
*/
public static <T> T getInstance(Class<T> cls) {
try {
T obj = createInstance(cls);
Field[] fields = cls.getDeclaredFields();
for (Field f : fields) {
if (f.isAnnotationPresent(SimpleInject.class)) {
if (!f.isAccessible()) {
f.setAccessible(true);
}
Class<?> fieldCls = f.getType();
f.set(obj, getInstance(fieldCls));
}
}
return obj;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
4、定义被具体的service
/**
* @Author Zzneko
* @Date 2022/9/9 17:00
**/
public class ServiceA {
@SimpleInject
ServiceB b;
public void callB(){
b.action();
}
public ServiceB getB() {
return b;
}
}
/**
* @Author Zzneko
* @Date 2022/9/9 17:01
**/
public class ServiceB {
public void action(){
System.out.println("I'm B");
}
}
切面常量
public enum InterceptPoint {
BEFORE,AFTER,EXCEPTION
}
测试
/**
* @Author Zzneko
* @Date 2022/9/9 17:04
**/
public class ProgramEntering {
public static void main(String[] args) {
ServiceA a = CGLibContainer.getInstance(ServiceA.class);
a.callB();
}
}
结果
entering ServiceA::callB, args: []
entering ServiceB::action, args: []
I’m B
leaving ServiceB::action, result: null
leaving ServiceA::callB, result: null