动态代理
静态代理
package cn.cdqf.proxy;
public interface ScanService {
void scan();
}
package cn.cdqf.proxy;
/**
* 被代理类
*/
public class ScanServiceImpl implements ScanService{
public void scan(){
//非业务逻辑 不应该跟业务逻辑代码耦合...
//System.out.println("记录:某某某---2020-12-10访问了篮球方面");
System.out.println("某某某需要篮球方面的数据");
//非业务逻辑 不应该跟业务逻辑代码耦合...
//System.out.println("记录:某某某---2020-12-10结束了访问");
}
}
package cn.cdqf.proxy;
/**
* 应该与被代理类实现同一个接口
* 这样才能在一定程度上保证 方法规则统一性
*
* 完全可以在这个类上面去做标记 告诉spring我要代理哪个类,被代理的类压根不知道什么情况
*
* 每个接口下面都会有自己的方法,你这里得调用具体得方法,所以只能代理一类对象,
* 静态得写死方法名,静态的代理一类对象
*/
public class ScanServiceImplProxy implements ScanService{
private ScanService scanService;
public ScanServiceImplProxy(ScanService scanService){
this.scanService = scanService;
}
@Override
public void scan() {
System.out.println("记录:某某某---2020-12-10访问了篮球方面");
scanService.scan();
System.out.println("记录:某某某---2020-12-10结束了访问");
}
}
package cn.cdqf.proxy;
public class Test {
public static void main(String[] args) {
ScanService scanService = new ScanServiceImpl();
//如果是通过spring框架来实现,@Autowired ScanService scanService
//用户想要这样一个对象,而且在最开始创建的时候,我们可以使用标记的办法告诉spring别用我自己
//用代理类,spring放入ioc容器中的已经是代理类
ScanService scanServiceProxy = new ScanServiceImplProxy(scanService);
scanServiceProxy.scan();
}
}
动态代理
1.你调用哪个方法,我就获得这个方法,方法对象method.invoke
2.程序员不手写类,让java帮我们生成,类加载器ClassLoader
这些功能java都已经提供好了类来实现
静态代理:只能代理一部分类,需要我们去写好整个要生成class的java文件
动态代理:可以代理任意类,我们只需要告诉程序生成class的必要条件
有两个方案,可以实现我们告诉程序这些必要条件
jdk动态代理,cglib动态代理
jdk动态代理
package cn.cdqf.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 步骤
* 1.实现InvocationHandler接口
*/
public class MyJdkProxy implements InvocationHandler {
Object object;
//object:被代理的类
public MyJdkProxy(Object object){
this.object = object;
}
/**
* 增强一个方法:在方法前,方法正常结束后,方法抛异常后,方法无论抛不抛异常后
* @param proxy
* @param method:代表现在正在调用的方法
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强的逻辑
System.out.println("方法调用前增强逻辑。。。。");
//增强不增强,原来的逻辑不能变,原方法该调用还得调用 调用的原来scan
Object invoke = method.invoke(object, args);
System.out.println("方法调用后增强逻辑。。。。");
return invoke;
}
//把被代理类给我了 我要调用一个方法去生成代理类
public Object getInstance(){
//proxy是jdk提供的代理类,生成代理类的方法
//因为要求方法名相同:jdk选择了接口
/**
* 类加载:加载功能
* 被代理类实现的接口:为了统一方法名
* 代理的功能,要如何增强,大家都乱写jdk不知道写在哪里的,jdk就要求必须传一个实现了
* InvocationHandler的类,然后把增强逻辑写在invoke方法中
*
* jdk生成的代理类 会跟被代理类实现同一个接口
*/
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces()
,this);
}
}
public static void main(String[] args) {
//被代理类
ScanService scanService = new ScanServiceImpl();
//能生成动态代理功能的类 先创建出来
MyJdkProxy myJdkProxy = new MyJdkProxy(scanService);
ScanService instance = (ScanService)myJdkProxy.getInstance();
instance.scan();
//System.out.println(instance);
}
细节:
package cn.cdqf.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 步骤
* 1.实现InvocationHandler接口
*/
public class MyJdkProxy<T> implements InvocationHandler {
//Object object;
T object;
//object:被代理的类
public MyJdkProxy(T object){
this.object = object;
}
/**
* 增强一个方法:在方法前,方法正常结束后,方法抛异常后,方法无论抛不抛异常后
* @param proxy
* @param method:代表现在正在调用的方法
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强的逻辑
System.out.println("方法调用前增强逻辑。。。。");
//增强不增强,原来的逻辑不能变,原方法该调用还得调用 调用的原来scan
try {
Object invoke = method.invoke(object, args);
System.out.println("正常结束方法增强的逻辑");
return invoke;//方法原来的返回值
}catch (Exception e){
System.out.println("异常结束后执行了逻辑");
}finally {
System.out.println("不管有没有异常都执行的逻辑");
}
System.out.println("方法调用后增强逻辑。。。。");
return null;
}
//把被代理类给我了 我要调用一个方法去生成代理类
public T getInstance(){
//proxy是jdk提供的代理类,生成代理类的方法
//因为要求方法名相同:jdk选择了接口
/**
* 类加载:加载功能
* 被代理类实现的接口:为了统一方法名
* 代理的功能,要如何增强,大家都乱写jdk不知道写在哪里的,jdk就要求必须传一个实现了
* InvocationHandler的类,然后把增强逻辑写在invoke方法中
*
* jdk生成的代理类 会跟被代理类实现同一个接口
*/
return (T)Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces()
,this);
}
}
cglib动态代理
1.asm字节码技术实现,jdk内部实现
2.asm生成的代理类是被代理类的子类,jdk生成是兄弟类,跟被代理类实现同一个接口
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
package cn.cdqf.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
//被代理类
private Object object;
public CglibProxy(Object object){
this.object = object;
}
public Object getObject(){
Enhancer enhancer = new Enhancer();
//被代理类的子类 所有被代理类是代理类的父类
enhancer.setSuperclass(object.getClass());
//指定怎么增强
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("方法执行前加逻辑");
//调用本来的方法
Object invoke = method.invoke(object, args);
System.out.println("方法执行后加逻辑");
return invoke;
}
}
//被代理类
ScanService scanService = new ScanServiceImpl();
CglibProxy cglibProxy = new CglibProxy(scanService);
ScanService scanService1 =(ScanService)cglibProxy.getObject();
scanService1.scan();