创作人 Leo
编辑时间 Wed Jan 1,2020 at 10:13
面向切面编程 AOP 为 OOP 的一种扩展
场景:
一个应用在某些操作需要加如日志功能
传统的oop做法为在每一个操作中加上日志功能,其实也可以单独写一个日志类,但这样就使业务类和日志类强关联了,就不够OO了
AOP提供了一种思想,将日志这种碎片功能以切面(在一个业务逻辑中插入一个小块)的方式插入到需要的操作中
java的实现是使用代理Proxy类实现
Proxy:
在网上摘抄了一段java代理的解释
1.什么是动态代理?
答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
2.为什么使用动态代理?
答:因为动态代理可以对请求进行任何处理
3.使用它有哪些好处?
答:因为动态代理可以对请求进行任何处理
4.哪些地方需要动态代理?
答:不允许直接访问某些类;对访问要做特殊处理等
具体做法就是在代理中invoke实际功能函数的前后加入碎片功能,也就是我们需要实现的切面
示例java代码:
首先编写我们的业务接口(StudentInfoService.java)
public interface StudentInfoService{
void findInfo(String studentName);
}
及其实现类(StudentInfoServiceImpl.java)
public class StudentInfoServiceImpl implements StudentInfoService{
public void findInfo(String name){
System.out.println("你目前输入的名字是:"+name);
}
}
处理拦截目的的类(MyHandler.java)
import org.apache.log4j.Logger;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
public class MyHandler implements InvocationHandler{
private Object proxyObj;
private static Logger log=Logger.getLogger(MyHandler.class);
public Object bind(Object obj){
this.proxyObj=obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
Object result=null;
try{
//请在这里插入代码,在方法前调用
("调用log日志方法"+method.getName());
result=method.invoke(proxyObj,args); //原方法
//请在这里插入代码,方法后调用
}catch(Exception e){
e.printStackTrace();
}
return result;
}
}
我们实现一个工厂,为了方便我们使用该拦截类(AOPFactory.java)
public class AOPFactory{
private static Object getClassInstance(String clzName){
Object obj=null;
try{
Class cls=Class.forName(clzName);
obj=(Object)cls.newInstance();
}catch(ClassNotFoundException cnfe){
System.out.println("ClassNotFoundException:"+cnfe.getMessage());
}catch(Exception e){
e.printStackTrace();
}
return obj;
}
public static Object getAOPProxyedObject(String clzName){
Object proxy=null;
MyHandler handler=new MyHandler();
Object obj=getClassInstance(clzName);
if(obj!=null) {
proxy=handler.bind(obj);
}else{
System.out.println("Can't get the proxyobj");
//throw
}
return proxy;
}
}
基本的拦截与其工厂我们都实现了,现在测试(ClientTest.java)
public class ClientTest{
public static void main(String[] args){
StudentInfoService studentInfo= (StudentInfoService)AOPFactory.getAOPProxyedObject("StudentInfoServiceImpl");
studentInfo.findInfo("阿飞");
}
}
php 可以通过反射的形式实现一个面向切面的程序
示例PHP代码:
<?php
/**
* Class Person
* 业务类
*/
class Person{
function say( $content ) {
echo $content , "<br />" ;
}
}
/**
* Class Log
* 日志工具类
*/
class Log{
public static $_L_ERR = 1 ;
public static $_L_NOTICE = 2 ;
public static function write($content, $level=null){
if ($level == null)
$level = self::$_L_NOTICE ;
echo 'level = ' . $level . ', content is '. $content ;
}
}
/**
* Class Handler
* 代理句柄
*/
class ProxyHandler{
private $obj ;
private $_obj ;
public function __construct( $class )
{
$this->obj = new ReflectionClass($class) ;
$this->_obj = new $class();
}
public function __call($name, $arguments)
{
// TODO: Implement __call() method.
// 在这里插入碎片程序
Log::write("这里插入碎片程序,比如日志 <br />");
$method = $this->obj->getMethod($name) ;
$r = $method->invokeArgs($this->_obj, $arguments);
// 或者在这里插入碎片程序
return $r ;
}
}
/**
* Class AopFactory
* 切面代理工厂
*/
class AopFactory{
public static function getProxy($class){
if (!is_string($class)){
throw new Exception('require a class name') ;
}
return new ProxyHandler($class) ;
}
}
$p1 = AopFactory::getProxy('Person') ;
$p1->say('hello');
?>