动态代理
AOP概念解释
AOP用在哪些方面:AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制,异常处理等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
AOP中的概念
Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象。
joinpoint(连接点):所谓连接点是指那些被拦截到的点(可以是方法、属性、或者类的初始化时机(可以是Action层、Service层、dao层))。在Spring中,这些点指的是方法,因为Spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器。
Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义,也即joinpoint的集合。
Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知。通知分为前置通知、后置通知、异常通知、最终通知、环绕通知。我们就以CGlibProxyFactory类的代码为例进行说明:
public class CGlibProxyFactory implements MethodInterceptor {
private Object targetObject; // 代理的目标对象
public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.targetObject.getClass()); // 设置目标类为代理对象的父类
enhancer.setCallback(this);
return enhancer.create();
}
// 从另一种角度看: 整个方法可看作环绕通知
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
PersonServiceBean bean = (PersonServiceBean)this.targetObject;
Object result = null;
if (bean.getUser() != null) { // 有权限
// ...... advice() ----> 前置通知(所谓通知,就是我们拦截到业务方法之后所要干的事情)
try {
result = methodProxy.invoke(targetObject, args); // 把方法调用委派给目标对象
// ...... afteradvice() ----> 后置通知
} catch (RuntimeException e) {
// ...... exceptionadvice() ----> 异常通知
} finally {
// ...... finallyadvice() ----> 最终通知
}
}
return result;
}
}
Target(目标对象):代理的目标对象。
Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入。
Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期为类(代理类)动态地添加一些方法或Field。
AOP带来的好处:降低模块的耦合度;使系统容易扩展;更好的代码复用性。
2. JDK实现
1). 创建Person接口
public interface PersonService {
/**
* 保存
* @param name 名称
*/
public void save(String name);
/**
* 根据ID更新名称
* @param name 姓名
* @param personId 人员ID
*/
public void update(String name, Integer personId);
/**
* 根据ID获取名称
* @param personId 人员ID
* @return 名称
*/
public String getPersonName(Integer personId);
}
2). 创建实现Person接口的实现类PersonImpl
public class PersonServiceImpl implements PersonService{
private String user = null;
public void setUser(String user) {
this.user = user;
}
public String getUser() {
return user;
}
public PersonServiceImpl() { }
public PersonServiceImpl(String user){
this.user = user;
}
@Override
public void save(String name) {
System.out.println("我是save方法");
}
@Override
public void update(String name, Integer personId) {
System.out.println("我是update方法");
}
@Override
public String getPersonName(Integer personId) {
System.out.println("我是getPersonName方法");
return "xxx";
}
}
3). 创建代理类PersonServiceImplProxy
public class PersonServiceImplProxy implements InvocationHandler {
private PersonService personService;
public PersonService createProxy(PersonService personService) {
return (PersonService) Proxy.newProxyInstance(PersonServiceImplProxy.class.getClassLoader(), personService.getClass().getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
PersonServiceImpl pImpl = (PersonServiceImpl) this.personService;
Object result = null;
// 如果不等于null则表示有权限
if (null != pImpl.getUser()) {
// 执行方法
result = method.invoke(personService, args);
}
return result;
}
}
4). 创建Demo类测试
public class Demo {
public static void main(String[] args) {
PersonServiceImplProxy proxy = new PersonServiceImplProxy();
PersonService service = proxy.createProxy(new PersonServiceImpl("mazaiting"));
service.save("123");
}
}
打印结果:
5). 更改测试代码
public class Demo {
public static void main(String[] args) {
PersonServiceImplProxy proxy = new PersonServiceImplProxy();
PersonService service = proxy.createProxy(new PersonServiceImpl());
service.save("123");
}
}
打印结果:
3. CGlib实现AOP功能
动态代理技术只能是基于接口,那如果这个对象没有接口,就要使用CGlib这个工具包。
1). 创建PersonService类
public class PersonService {
private String user = null;
public void setUser(String user) {
this.user = user;
}
public String getUser() {
return user;
}
public PersonService() { }
public PersonService(String user){
this.user = user;
}
public void save(String name) {
System.out.println("我是save方法");
}
public void update(String name, Integer personId) {
System.out.println("我是update方法");
}
public String getPersonName(Integer personId) {
System.out.println("我是getPersonName方法");
return "xxx";
}
}
2). 创建CGlibProxyFactory类
public class CGlibProxyFactory implements MethodInterceptor {
// 代理的目标对象
private Object targetObject;
public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
// 该类用于生成代理对象
Enhancer enhancer = new Enhancer();
// 设置目标类为代理对象的父类
enhancer.setSuperclass(this.targetObject.getClass());
// 设置回调用对象本身
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
PersonService service = (PersonService) this.targetObject;
Object result = null;
// 有权限
if (null != service.getUser()) {
// 把方法调用委派给目标对象
result = methodProxy.invoke(targetObject, args);
}
return result;
}
}
3). 创建Demo测试类
public class Demo {
public static void main(String[] args) {
CGlibProxyFactory factory = new CGlibProxyFactory();
PersonService service = (PersonService) factory.createProxyInstance(new PersonService("mazaiting"));
service.save("999");
}
}
4). 打印结果