AOP面向切面 Java代理
通过spring进行配置
https://blog.youkuaiyun.com/wilbur_xieyj/article/details/88981453
静态代理
- 定义接口
package cn.edu.zucc.blog.dao;
/**
* 定义一个用户接口
* @author xyj
*/
public interface UserDao {
public void addUser();
public void removeUser();
}
- 实现接口
package cn.edu.zucc.blog.dao;
/**
* userDao接口的实现类
* @author xyj
*/
public class UserDaoImpl implements UserDao{
@Override
public void addUser() {
System.out.println("this is addUser");
}
@Override
public void removeUser() {
System.out.println("this is removeUser");
}
}
- 定义接口的代理类,在原方法调用之前和之后加入预处理与调用结束之后的操作
package cn.edu.zucc.blog.staticProxy;
import cn.edu.zucc.blog.dao.UserDao;
/**
* 通过组合原有实现类的方式实现静态代理
* @author xyj
*/
public class UserDaoProxy implements UserDao {
private UserDao userDao;
/**
* 获取原本调用的实现类
* @param userDao 原有实现类
*/
public UserDaoProxy(UserDao userDao){
this.userDao=userDao;
}
@Override
public void addUser() {
//前置操作
System.out.println("before : addUser");
//调用原有方法
userDao.addUser();
//后置操作
System.out.println("after : addUser");
}
@Override
public void removeUser() {
//前置操作
System.out.println("before : removeUser");
//调用原有方法
userDao.removeUser();
//后置操作
System.out.println("after : removeUser");
}
}
- 测试Test
package cn.edu.zucc.blog.staticProxy;
import cn.edu.zucc.blog.dao.UserDao;
import cn.edu.zucc.blog.dao.UserDaoImpl;
public class Test {
public static void main(String[] args) {
//创建原有方法
UserDao dao = new UserDaoImpl();
//创建代理类
UserDao userDao = new UserDaoProxy(dao);
//通过代理类实现方法
userDao.addUser();
userDao.removeUser();
}
}
静态代理太过麻烦了,而且只能对应代理一个接口。所以看看就行。
JDK动态代理
- 首先接口与实现类与之前一致不做更改
- 静态代理方法放弃,改用JDK代理,继承InvocationHandler 这里用的是JDK代理小心导错包
package cn.edu.zucc.blog.jdkProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* JDK代理
* 注:只能代理接口中定义的方法
* @author xyj
*/
public class UserJDKProxy implements InvocationHandler {
private Object target;
/**
* 获取原本调用的实现类
* @param target 原有实现类
*/
public UserJDKProxy(Object target){
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置操作
System.out.println("before method : "+method.getName());
//通过反射调用原本使用的方法
Object result = method.invoke(target,args);
//后置操作
System.out.println("after method");
return result;
}
}
- 测试Test
package cn.edu.zucc.blog.jdkProxy;
import cn.edu.zucc.blog.UserDao;
import cn.edu.zucc.blog.UserDaoImpl;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
//动态代理
UserDao userDao = (UserDao) Proxy.newProxyInstance(
//指定当前目标对象使用的类加载器,获取加载器的方法是固定的
UserDao.class.getClassLoader(),
//指定目标对象实现的接口类型,使用泛型方式确认类型
new Class[]{UserDao.class},
//指定动态处理器,执行目标对象方法时会触发事件处理器的方法
new UserJDKProxy(
//目标接口的实现类
new UserDaoImpl()
)
);
userDao.addUser();
userDao.removeUser();
}
}
CGLIB动态代理
cglib是针对类进行代理,不局限与接口,它通过实现对指定类通过继承生成一个子类,并覆盖原有方法来实现代理
- 首先接口与实现类与之前一致不做更改
- 使用CGLIB代理,注意这边导的包已经变成cglib的了
package cn.edu.zucc.blog.CGLIBProxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* CGLIB代理
* @author xyj
*/
public class UserCglibProxy implements MethodInterceptor {
private Object target;
/**
* 获取原本调用的实现类
* 相当于JDK代理当中的构造器
* @param target 原有实现类
*/
public Object getInstance(Object target){
//给代理对象赋值
this.target=target;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//前置操作
System.out.println("before method : "+method.getName());
//通过反射调用原有方法
Object o1 = methodProxy.invokeSuper(o, objects);
//后置操作
System.out.println("after method");
return o1;
}
}
- Test测试方法
package cn.edu.zucc.blog.CGLIBProxy;
import cn.edu.zucc.blog.UserDaoImpl;
public class Test {
public static void main(String[] args) {
//动态代理
UserCglibProxy userCglibProxy = new UserCglibProxy();
//创建即将被代理的类
UserDaoImpl userDaoImpl = new UserDaoImpl();
//获取代理对象
UserDaoImpl user = (UserDaoImpl) userCglibProxy.getInstance(userDaoImpl);
//调用方法
user.addUser();
user.removeUser();
}
}
总结
静态代理太麻烦
JDK通过接口中方法实现,无法代理实体类
CGLIB通过继承的方法创建被代理对象的子类,重写原有方法。final方法无法继承,所以无法被代理
据说CGLIB要比JDK的慢一点,还有待深入研究