Java实现AOP面向切面编程的实例教程

网友投稿 200 2023-07-18


Java实现AOP面向切面编程的实例教程

介绍

众所周知,AOP(面向切面编程)是Spring框架的特色功能之一。通过设置横切关注点(cross cutting concerns),AOP提供了极高的扩展性。那AOP在Spring中是怎样运作的呢?当你只能使用core java,却需要AOP技术时,这个问题的解答变得极为关键。不仅如此,在高级技术岗位的面试中,此类问题也常作为考题出现。这不,我的朋友最近参加了一个面试,就被问到了这样一个棘手的问题——如何在不使用Spring及相关库,只用core Java的条件下实现AOP。因此,我将在本文中提供一份大纲,帮助大家了解如何只用core Java实现一个AOP(当然啦,这种AOP在功能上有一定的局限性)。注意,本文不是一篇有关Spring AOP与Java AOP的对比研究,而是有关在core Java中借助固有的设计模式实现AOP的教程。

想必读者已经知道AOP是什么,也知道在Spring框架中如何使用它,因此本文只着眼于如何在不用Spring的前提下实现AOP。首先,我们得知道,Spring是借助了JDK proxy和CGlib两种技术实现AOP的。JDK dynamic proxy提供了一种灵活的方式来hook一个方法并执行指定的操作,但执行操作时得有一个限制条件:必须先提供一个相关的接口以及该接口的实现类。实践出真知,让我们透过一个案例来理解这句吧!现在有一个计算器程序,用于完成一些数学运算。让我们来考虑下除法功能,此时的问题是:如果core framework 已经具备了一份实现除法的代码,我们能否在代码执行时劫持(highjack)它并执行额外的校验呢?答案是肯定的,我将用下面提供的代码片段来证明这点。首先来看基础接口的代码:

public interface Calculator {

public int calculate( int a , int b);

}

该接口实现类的代码如下:

publihttp://c class CalculatorImpl implements Calculator {

@Override

public int calculate(int a, int b) {

return a/b;

}

}

假设我们既不能修该上面的代码,也不能对核心库进行任何改动,怎样才能完美地实现校验功能呢?不如试下JDK dynamic proxy的功能吧。

public class SomeHandler implements InvocationHandler {

// Code omitted for simplicity…..

@Override

public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {

// Your complex business validation and logic

Object result = method.invoke(targetObject ,params);

return result;

}

}

让我们通过测试类来看看由JDK dynamic proxy实现的校验功能的效果如何。

public static void main(String[] args) {

CalculatorImpl calcImpl = new CalculatorImpl();

Calculator proxied = (Calculator)ProxyFactory.getProxy (Calculator.class, calcImpl,

new SomeHandler(calcImpl));

int result = proxied.calculate(20, 10);

System.out.println("FInal Result :::" + result);

}

从结果可以看出,简单地实现功能强大的InvocationHandler接口,我们便能得到一个hooking implementation。按照JDK文档的描述,InvocationHandler接口是借助一个代理实例(proxy instance)来处理一个方法调用的。

创建一个抽象类,用于将aop应用于目标对象上。

创建名为BeforeHandler 和 AfterHandler的两个aop。前者在方法执行之前工作,而后者则在方法执行结束后工作。

创建一个代理类,使所有的aop handler和目标对象只需作为参数传入,就能创建一个hook。

加入你自己的业务逻辑或者横切关注点。

最后,通过传入相关的参数创建代理对象(proxy object)。

两种实现AOP的方式:

1,JDK提供的动态代理实现  

接口

public interface UserBean

{

void getUser();

void addUser();

void updateUser();

void deleteUser();

}

原始实现类

public class UserBeanImpl implements UserBean

{

private String user = null;

public UserBeanImpl()

{

}

public UserBeanImpl(String user)

{

this.user = user;

}

public String getUserName()

{

return user;

}

public void getUser()

{

System.out.println("this is getUser() method!");

}

public void setUser(String user)

{

this.user = user;

System.out.println("this is setUser() method!");

}

public void addUser()

{

System.out.println("this is addUser() method!");

}

public void updateUser()

{

System.out.println("this is updateUser() method!");

}

public void deleteUser()

{

System.out.println("this is deleteUser() method!");

}

}

代理类

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import com.cignacmc.finance.bean.UserBeanImpl;

public class UserBeanProxy implements InvocationHandler

{

private Object targetObject;

public UserBeanProxy(Object targetObject)

{

this.targetObject = targetObject;

}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

{

UserBeanImpl userBean = (UserBeanImpl) targetObject;

String userName = userBean.getUserName();

Object result = null;

//权限判断

if(userName != null && !"".equals(userName))

{

result = method.invoke(targetObject, args);

}

return result;

}

}

测试类

import java.lang.reflect.Proxy;

import com.cignacmc.finance.bean.UserBean;

import com.cignacmc.finance.bean.UserBeanImpl;

import com.cignacmc.finance.proxy.UserBeanProxy;

public class ProxyExe

{

public static void main(String[] args)

{

System.out.println("Proved.............");

UserBeanImpl targetObject = new UserBeanImpl("Bob Liang");

UserBeanProxy proxy = new UserBeanProxy(targetObject);

//生成代理对象

UserBean object = (UserBean)Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),

targetObject.getClass().getInterfaces(), proxy);

object.addUser();

System.out.println("NO Proved.............");

targetObject = new UserBeanImpl();

proxy = new UserBeanProxy(targetObject);

//生成代理对象

object = (UserBean)Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),

targetObject.getClass().getInterfaces(), proxy);

object.addUser();

}

}

输出:

Proved.............

this is addUser() method!

NO Proved.............

从上面这个例子可以成功拦截了调用的方法addUser()并对其做了相应的处理

2, 通过cglib创建代理类

好处是不要求我们的目标对象实现接口 

原始类

public class ClientBean

{

private String name = null;

public ClientBean()

{

}

public ClientBean(String name)

{

this.name = name;

}

public void addClient()

{

System.out.println("this is addClient() method!");

}

public void deleteClient()

{

System.out.println("this is deleteClient() method!");

}

public void getClient()

{

System.out.println("this is getClient() method!");

}

public void updateClient()

{

System.out.println("this is updateClient() method!");

}

public String getClientName()

{

return name;

}

public void setClientName(String name)

{

this.name = name;

}

}

代理类

import java.lang.reflect.Method;

import com.cignacmc.finance.bean.ClientBean;

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

public class CGLibProxy implements MethodInterceptor

{

private Object targetObject;

public Object createProxyObject(Object targetObject)

{

this.targetObject = targetObject;

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(this.targetObject.getClass());

enhancer.setCallback(this);

return enhancer.create();

}

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable

{

ClientBean clientBean = (ClientBean)targetObject;

String userName = clientBean.getClientName();

Object result = null;

if(userName != null && !"".equals(userName))

{

result = method.invoke(targetObject, args);

}

return result;

}

}

测试类

import java.lang.reflect.Proxy;

import com.cignacmc.finance.bean.ClientBean;

import com.cignacmc.finance.bean.UserBean;

import com.cignacmc.finance.bean.UserBeanImpl;

import com.cignacmc.finance.proxy.CGLibProxy;

import com.cignacmc.finance.proxy.UserBeanProxy;

public class ProxyExe

{

public static void main(String[] args)

{

System.out.println(".............CGLIB Proxy....................");

System.out.println("Proved....................");

CGLibProxy cproxy = new CGLibProxy();

ClientBean clientBean = (ClientBean)cproxy.createProxyObject(new ClientBean("Bob Liang"));

clientBean.addClient();

System.out.println("NO Proved....................");

cproxy = new CGLibProxy();

clientBean = (ClientBean)cproxy.createProxyObject(new ClientBean());

clientBean.addClient();

}

}

输出:

.............CGLIB Proxy....................

Proved....................

this is addClient() method!

NO Proved....................


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Dwr3.0纯注解(纯Java Code配置)配置与应用浅析二之前端调用后端
下一篇:java验证码生成具体代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~