代理可以解决这些 臃肿冗余的问题。
概念
在不修改目标类的目标非凡代码前提下,为目标方法增加额外功能
代理类中必须也有同样的目标方法
- 代理类实现跟目标类同样的接口
- 若目标类没有实现接口,代理类继承目标类
实现方案:静态代理和动态代理
静态代理 (Static Proxy)
需要手动编写代理类 ,基本上 一个目标类就要编写一个代理类
动态代理 (Dynamic Proxy)
动态代理解决方案中有2种一种是JDK、CGLib 性能上肯定是JDK性能更高,所以尽量用JDK但是JDK适用场景是接口
JDK
代理类实现跟目标类一样的接口
@Test
public void test() {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 传入类型 可以不用强转了
UserServiceImpl target = ctx.getBean("userService", UserServiceImpl.class);
// target.login("wpp","123");
/**
* public static Object newProxyInstance(ClassLoader loader,
* Class<?>[] interfaces,
* InvocationHandler h)
* throws IllegalArgumentException
*/
// Proxy.newProxyInstance(getClass().getClassLoader(),)
// Class<?>[] cls = target.getClass().getInterfaces();
// System.out.println(cls); // 如果没有实现某个接口 则 cls是空的 下面代码崩溃啦 所以jdk主要用于接口
Object instance = Proxy.newProxyInstance(getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("匿名类 业务一");
// 其实这个result 类型就是 UserServiceImpl 类型
Object result = method.invoke(target,args);
System.out.println("匿名类 业务二");
return result;
}
});
System.out.println("instance:" + instance);
if (instance instanceof UserServiceImpl) {
System.out.println("是UserServiceImpl 类");
} else {
System.out.println("是Proxy类");
}
if (instance.getClass() == UserServiceImpl.class) {
System.out.println("是的");
} else {
System.out.println("是Proxy类");
}
// 虽然instance 不是 UserServiceImpl类型 但是实现同样接口 所以可以用 接口类型取转
UserService userService = (UserService)instance;
userService.login("wpp","123");
// 关闭容器
ctx.close();
}
CGLib
可以解决 接口和继承的情况 BeanPostProcessor
在实现 BeanPostProcessor 中在 postProcessAfterInitialization实现
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization");
// System.out.println(bean);
// com.mj.service.impl.UserServiceImpl@7133da86
// System.out.println(beanName);
// userService
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(getClass().getClassLoader());
enhancer.setSuperclass(bean.getClass());
// 这块 也可以像ppt 和mj老师那样写一个类 implements MethodInterceptor
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// System.out.println(method);
System.out.println(method.getName());
if (method.getName().equals("login") || method.getName().equals("save")) {
System.out.println("匿名类 业务一");
}
Object result = method.invoke(bean, objects);
if (method.getName().endsWith("ter")) {
System.out.println("匿名类 业务二");
}
System.out.println("result:" + result);
return result;
}
});
// return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
return enhancer.create();
}
个人总结一波:
代理就是帮你做事情,可以自己手动搞静态代理 也可以通过动态代理。 动态代理区分接口/继承2种情况,jdk自带只能实现接口的。而spring中的cglib可以实现2种。