AOP技术应用和研究--动态代理

在SpringAop的实现中,我们首先需要知道的就是动态代理。

1,cglib动态代理

先看一个简单的cglib动态代理实例,我们假设的场景是在web开发中,用户实体访问数据库的Dao层UserDao实现事务处理这项功能。具体代码如下:

package cn.miao.proxy.cglib;

public class User {
	private String username;
	private String password;
	
	public User(String username, String password) {
		this.username = username;
		this.password = password;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	
}
package cn.miao.proxy.cglib;
/**
 * 事务处理类
 * @author demiaowu
 *
 */
public class Transaction {
	
	public void beginTransaction() {
		System.out.println("begin transaction");
	}
	
	public void commit() {
		System.out.println("commit");
	}
}

package cn.miao.proxy.cglib;

import org.junit.Test;
/**
 * cglib动态代理示例测试客户端
 * @author demiaowu
 *
 */
public class UserClient {
	
	@Test
	public void clientTest() {
		User user = new User("demiaowu","123456");
		//实例化transaction
		Transaction transaction = new Transaction();
		UserDaoImpl target = new UserDaoImpl();
		UserMethodInterceptor inteceptor = new UserMethodInterceptor(transaction, target);
		UserDaoImpl proxy = (UserDaoImpl) inteceptor.getProxy();
		proxy.saveUser(user);
	}
}

package cn.miao.proxy.cglib;

public class UserDaoImpl{

	public void saveUser(User user) {
		System.out.println("saveUser");
	}

	public void updateUser(User user) {
		System.out.println("updateUser");
	}

	public void deleteUser(String username) {
		System.out.println("deleteUser");
	}

}

package cn.miao.proxy.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class UserMethodInterceptor implements MethodInterceptor {
	private Transaction transaction;
	private Object target;
	
	public UserMethodInterceptor(Transaction transaction, Object target) {
		this.transaction = transaction;
		this.target = target;
	}
	public Object getProxy() {
		Enhancer enhancer = new Enhancer();
		//设置需要创建子类的类
		enhancer.setSuperclass(this.target.getClass());
		enhancer.setCallback(this);
		//通过字节码技术动态创建子类实例
		return enhancer.create();
	}
	public Object intercept(Object arg0, Method method, Object[] arg2,
			MethodProxy proxy) throws Throwable {
		Object retValue;
		String methodName = method.getName();
		if ("saveUser".equals(methodName) || "updateUser".equals(methodName) || "deleteUser".equals(methodName)) {
			this.transaction.beginTransaction();
			retValue = method.invoke(this.target, arg2);
			this.transaction.commit();
		} else {
			retValue = method.invoke(this.target, arg2);
		}
		return retValue;
	}
}
写的 jdk 实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,就需要 cglib 了。 cglib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。

cglib包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。其原理是Enhancer类通过字节码技术为原有的类创建子类,并且设置好callbackproxy,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxyintercept()函数。

2,jdk动态代理

直接看例子吧。
package cn.miao.proxy.jdk;
/**
 * 事务处理类
 * @author demiaowu
 *
 */
public class Transaction {
	
	public void beginTransaction() {
		System.out.println("begin transaction");
	}
	
	public void commit() {
		System.out.println("commit");
	}
}
package cn.miao.proxy.jdk;
/**
 * 用户类
 * @author demiaowu
 *
 */
public class User {
	private String username;
	private String password;
	
	public User(String username, String password) {
		this.username = username;
		this.password = password;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	
}

package cn.miao.proxy.jdk;



import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

import org.junit.Test;
/**
 * 客户端测试类
 * @author demiaowu
 *
 */
public class UserClient {
	
	@Test
	public void clientTest() {
		User user = new User("demiaowu","123456");
		//实例化transaction
		Transaction transaction = new Transaction();
		//实例化目标对象
		UserDao target = new UserDaoImpl();
		//实例化InvocationHandler
		InvocationHandler userHandler = (InvocationHandler) new UserInvocationHandler(transaction, target);
		//生成代理对象
		UserDao proxy = (UserDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), userHandler);
		proxy.saveUser(user);
	}
}

package cn.miao.proxy.jdk;

public interface UserDao {

	public void saveUser(User user);
	public void updateUser(User user);
	public void deleteUser(String username);
}

package cn.miao.proxy.jdk;

public class UserDaoImpl implements UserDao {

	public void saveUser(User user) {
		System.out.println("saveUser");
	}

	public void updateUser(User user) {
		System.out.println("updateUser");
	}

	public void deleteUser(String username) {
		System.out.println("deleteUser");
	}

}

package cn.miao.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * User条用处理类
 * @author demiaowu
 *
 */
public class UserInvocationHandler implements InvocationHandler {
	private Transaction transaction;
	private Object target;
	
	public UserInvocationHandler(Transaction transaction, Object target) {
		this.transaction = transaction;
		this.target = target;
	}
	/**
	 * proxy 是Proxy类要为你生成的代理类实例
	 * method 条用的方法是Method的实例,如果调用saveUser()方法,那么就是saveUser()的Method实例
	 * args 调用方法传入的参数,如果调用saveUser(User user)方法,那么就是传入的参数user
	 * return 使用代理后将作为调用方法后的返回值,如果调用saveUser(User user)方法,那么就是它的返回值
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object retValue = null;
		String mehodName = method.getName();
		if ("saveUser".equals(mehodName) || "deleteUser".equals(mehodName) || "updateUser".equals(mehodName)) {
			this.transaction.beginTransaction();
			retValue = method.invoke(this.target, args);
			this.transaction.commit();
		} else {
			retValue = method.invoke(this.target, args);
		}
		return retValue;
	}

}

下面我们来看看了解下jdk动态代理的原理, 动态代理还要从 jdk 本身说起。在 jdk 的 java.lang.reflect 包下有个 Proxy 类, 它正是构造代理类的入口。这个类的结构如下图3.4:

从上图发现最后面四个是公有方法。而最后一个方法 newProxyInstance 就是创建代理对象的方法。这个方法的源码如下:

/**
 * loader:类加载器
 * interfaces:目标对象实现的接口
 * h:InvocationHandler的实现类
 */
public static Object newProxyInstance(ClassLoader loader,
					  Class<?>[] interfaces,
					  InvocationHandler h)
	throws IllegalArgumentException
    {
	…//省略
	Class cl = getProxyClass(loader, interfaces);
		try {
            // 生成代理对象的构造方法(也就是$Proxy4(InvocationHandler h))
	    Constructor cons = cl.getConstructor(constructorParams);
            // 生成代理类的实例并把UserInvocationHandler的实例传给它的构造方法
	    return (Object) cons.newInstance(new Object[] { h });
	} 
	…//省略
    }

这个方法需要三个参数:ClassLoader,用于加载代理类的Loader 类,通常这个 Loader 和被代理的类是同一个Loader 类。Interfaces,是要被代理的那些那些接口。InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,他也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler 类中定义的唯一方法 invoke 中。这在后面再详解。

首先getProxyClass()方法生成代理类的Class,然后代理类的Class使用getConstructor()方法生成代理类的构造函数,也就是$Proxy4(InvocationHandlerh) 如图3.5 Proxy,


最后cons.newInstance(newObject[]{h})生成代理类的实例并把UserInvocationHandler的实例传给它的构造方法。这就是Proxy生成代理对象的整个过程。下面看看Proxy如何产生代理类的过程,如图3.6,创建代理对象的时序图


getProxyClass()是生成的代理Class。 getProxyClass()方法核心代码如下图3.7:


在getProxyClass()中使用ProxyGenerator类的静态方法generateProxyClass(),这里是真正生成代理类class字节码的地方。最后defineClass0()根据字节码生成代理类实例。

现在,jdk是怎样动态生成代理类的字节的原理已经一目了然了。再来解决另外一个问题,那就是由谁来调用InvocationHandler的invoke方法的。要解决这个问题就要看一下jdk到底为我们生成了一个什么东西。实际上生成的$Proxy4继承了Proxy类和UserDao接口。并且有一个数据成员InvocationHandler如图3.5。$Proxy的构造函数如下:

public$Proxy4(InvocationHandler invocationhandler) {
       super(invocationhandler);
}


代理对象就是用上面的构造函数生成的。其中Proxy当然也生成了saveUser(User user)方法。这个方法实际上调用的就是UserInvocationHandler的invoke()方法。这样我们就把jdk和cglib动态代理的思想原理大致的描述完。


代码在:https://github.com/demiaowu/aop

jdk的示例代码代码在:src/cn/miao/proxy/jdk目录下面

cglib的示例代码在:src/cn/miao/proxy/cglib目录下面

AOP技术应用和研究系列博客 AOP技术应用和研究


深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值