springAOP的底层就是动态代理,在学习AOP之前还是需要将动态代理和静态代理进行一定的学习
代理模式:
- 静态代理
- 动态代理
静态代理
可以通过创建或工具生成代理类的源码,再编译代理类,即代理类和委托类的关系再程序运行前就已经存在
静态代理的好处
1.可以使得真实角色更加纯粹 . 将一些公共的事情交给代理类
2.实现了业务的分工,可以在不改变真实角色的情况下增加额外的操作
3.公共业务发生扩展时变得更加集中和方便 .
缺点
1.类多了 , 多了代理类 , 工作量变大了 . 开发效率降低
静态代理,在代码编译时就确定了被代理的类是哪一个。
静态代理比较简单,代理类和被代理类实现了同一接口,在代理类的构造函数中定义一个被代理类的对象即可。
代码演示:
被代理类实现的接口
public interface IUserInfoDao {
//保存的方法
public abstract void save(UserInfo userInfo);
//更新的方法
public abstract void update(UserInfo userInfo);
//查询 返回值是一个UserInfo对象
UserInfo queryByLoginName(String uname);
void demo();
}
被代理类
public class UserInfoDao implements IUserInfoDao {
@Override
public void save(UserInfo userInfo) {
System.out.println("UserInfoDao save method invoke");
}
@Override
public void update(UserInfo userInfo) {
System.out.println("UserInfoDao update method invoke");
}
@Override
public UserInfo queryByLoginName(String uname) {
return new UserInfo(2, "root2", "123456789", "James2", false);
}
@Override
public void demo(){
System.out.println("demo");
}
}
在上面前提下,当我们需要在实现类增加业务处理的时候(不修改源代码),创建一个实现相同接口的代理类,代理类中实现被代理类的原先功能。并增加一些功能
public class UserInfoDaoProxy implements IUserInfoDao {
private UserInfoDao userInfoDao=new UserInfoDao();
@Override
public void save(UserInfo userInfo) {
System.out.println("增加的功能");
userInfoDao.save(userInfo);
}
@Override
public void update(UserInfo userInfo) {
System.out.println("增加的功能");
userInfoDao.save(userInfo);
}
@Override
public UserInfo queryByLoginName(String uname) {
System.out.println("增加的功能");
return userInfoDao.queryByLoginName(uname);
}
@Override
public void demo() {
System.out.println("s");
}
}
那么我们在service层调用的时候,就可以调用我们写的静态代理类。
private IUserInfoDao userInfoDao=new UserInfoDaoProxy();
可以实现不改变源代码的情况下,进行业务的增强
动态代理
-
动态代理的角色和静态代理的一样 .
-
动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
-
动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
-
基于接口的动态代理----JDK动态代理
-
基于类的动态代理–cglib
在java的动态代理中,有两个重要的类和接口
InvocationHandler接口:调用处理程序
其中InvocationHandler是动态代理类都必须要实现的接口,通过代理对象调用一个方法的时候,该方法就会被转发由InvocationHandler这个接口的invoke方法来调用。
Object invoke(Object proxy, 方法 method, Object[] args);
参数:
proxy 调用该方法的代理实例
method 所述方法对应于调用代理实例上的接口方法
args 包含的方法调用传递代理实例的参数值
Proxy类:代理
Proxy类,动态创建一个代理对象的类,它提供了许多方法,用的最多的是newProxyInstance()方法,得到一个动态的代理对象。每个代理实例都有一个关联的调用处理程序对象,实现了InvocationHandler接口,调用处理程序的invoke方法
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
JDK代理
被代理类必须实现接口,没有接口的类,不能够被代理
public class ObjectJDKProxy {
//构造方法传入的参数是真实的对象
private Object object;
public ObjectJDKProxy(Object object){
this.object=object;
}
//获取动态代理
public Object getProxyObj(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new InvocationHandler() {
/**
*
* @param proxy 代理类
* @param method 执行的方法
* @param args 方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("ObjectJDKProxy代理的"+method.getName()+"方法执行。参数为:--->"+args);
return method.invoke(object,args);
}
});
}
}
调用:UserInfoService
//Service层
public class UserInfoService {
//JDK
private IUserInfoDao userInfoDao= (IUserInfoDao) new ObjectJDKProxy(new UserInfoDao()).getProxyObj();
//注册
public void register(UserInfo userInfo){
UserInfo dbui = userInfoDao.queryByLoginName(userInfo.getUname());
//如果传回来的不是null,说明存在该用户名
if (dbui!=null){
throw new RuntimeException("用户名已经存在");
}
//保存
userInfoDao.save(userInfo);
}
//登录 传入的参数是接受的UserInfo 返回值是数据库返回的UserInfo
public UserInfo login(UserInfo userInfo){
UserInfo dbui = userInfoDao.queryByLoginName(userInfo.getUname());
//说明用户名不存在
if (dbui==null){
throw new RuntimeException("用户名或密码错误(Dao返回的是null--用户名不存在)");
}
//dbui是数据库返回的UserInfo userInfo是登录的UserInfo
if (!dbui.getUpass().equals(userInfo.getUpass())){
throw new RuntimeException("用户名或密码错误(两个密码不一致)");
}
return dbui;
}
//更新
public void update(UserInfo userInfo){
userInfoDao.update(userInfo);
}
public void demo(){
System.out.println("demo");
}
}
测试类:
注意事项:
- 使用JDK动态代理,在使用强制类型转换的时候,接受类型必须使用接口,不能是被代理类
- 没有实现接口的使用JDK代理
代码测试注意事项
public class testJDK {
public static void main(String[] args) {
//没有实现接口的使用代理
Object proxyObj = new ObjectJDKProxy(new UserInfoService()).getProxyObj();
UserInfoService userInfoService= (UserInfoService) proxyObj;
System.out.println(proxyObj.getClass().getName());
}
}
报错:类型转换异常:代理类无法转换为UserInfoService类
数据类型转换
public class testJDK {
public static void main(String[] args) {
Object proxy= new ObjectJDKProxy(new UserInfoDao()).getProxyObj();
System.out.println(proxy.getClass().getName());//com.sun.proxy.$Proxy0
//使用接口接收
IUserInfoDao userInfoDao= (IUserInfoDao) new ObjectJDKProxy(new UserInfoDao()).getProxyObj();
System.out.println(userInfoDao.getClass().getName());//com.sun.proxy.$Proxy0
//使用被代理类接收
UserInfoDao userInfoDao2= (UserInfoDao) new ObjectJDKProxy(new UserInfoDao()).getProxyObj();
System.out.println(userInfoDao2.getClass().getName());
}
}
同样也是类型转换异常
CGLib代理
public class ObjectCGLibProxy {
private Object object;
//目标类 真实的对象 被代理的对象
public ObjectCGLibProxy(Object object){
this.object=object;
}
public Object getObject(){
Enhancer enhancer = new Enhancer();
//父类的class文件
enhancer.setSuperclass(object.getClass());
//回调方法 代理类的方法调用的时候,就会执行
//参数为Callback(接口)实现类 其中interface MethodInterceptor extends Callback
enhancer.setCallback(new MethodInterceptor() {
@Override
//Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy
//Object obj 是原始类
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable {
System.out.println("ObjectCGLibProxy代理的"+method.getName()+"方法执行。参数为:--->"+args);
return proxy.invokeSuper(obj, args);
//return proxy.invoke(object,args);
}
});
return enhancer.create();
}
}
CGLib代理则不存在上面的注意事项。数据类型可以使用被代理类,没有实现接口的也可以被动态代理
public class testCGLib {
public static void main(String[] args) {
Object proxy = new ObjectCGLibProxy(new UserInfoDao()).getObject();
System.out.println(proxy.getClass().getName());com.gx.dao.UserInfoDao$$EnhancerByCGLIB$$4ffc8a53
UserInfoDao userInfoDao= (UserInfoDao) proxy;
System.out.println(userInfoDao.getClass().getName());//com.gx.dao.UserInfoDao$$EnhancerByCGLIB$$4ffc8a53
userInfoDao.save(new UserInfo());
/* Method[] methods = userInfoDao.getClass().getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}*/
//无接口的类
Object proxyObj = new ObjectCGLibProxy(new UserInfoService()).getObject();
UserInfoService userInfoService= (UserInfoService) proxyObj;
System.out.println(userInfoService.getClass().getName());//com.gx.service.UserInfoService$$EnhancerByCGLIB$$738f0c95
userInfoService.demo();
//userInfoService.update(new UserInfo());
}
}