『壹』 java開發中,數據許可權是基於攔截器好還是基於切面好
攔截器好吧。
攔截器通過繼承或者實現框架現成的父攔截器介面來實現攔截功能(例如mybatisplus的InnerInterceptor介面),而切面底層是用到了反射,反射本身耗時更久,雖說影響不是特別大但是還是沒有直接實現父攔截器來得快。
而且切面的話你還要制訂切面的Pointcut規則,讓切入的方法都要滿足該規則,如果切的是註解的話還要在到處加註解,不如統一在攔截器里進行處理算了。
『貳』 spring框架的面向切面編程如何理解
Spring提供了對AOP技術的良好封裝,AOP稱為面向切面編程,就是系統中有很多各不相乾的類的方法,在這些眾多的方法中要加入某種系統功能代碼,例如:加入日誌、許可權判斷、異常處理等,這種應用成為AOP。
實現AOP功能採用的是代理技術,客戶端程序不再調用目標,而調用代理類,代理類與目標類對外具有相同的方法聲明,有兩種方式可以實現相同的方法聲明,一是實現相同的介面,而是作為目標的子類在JDK中採用Proxy類產生動態代理的方式為某個介面生成實現類,如果要為某類個生成子類,則可以用CGLIB。
在生成的代理類的方法中加入系統功能和調用目標類的相應方法,系統功能的代理以Advice對象進行提供,顯然要創建出代理對象,至少需要目標類和Advice類。
Sping提供了這種支持,只需要在Sping配置文件中配置這兩個元素即可實現代理和Aop功能,
例如:
<bean id = "proxy" type = "org.spring.framework.aop.ProxyBeanFacory">
<property name = "target" ref = ""></property>
<property name = "advisor" ref = ""></property>
</bean>
『叄』 什麼是面向切面編程
「面向切面編程」。只有當你真正的理解OOP之後,才可以理解AOP(面向切面編程)的思想。
這個思想,不是一兩句就能將的明白的。用個生活中的例子:
人的手可以寫字,並且可以用很多中筆來寫字。例如,鋼筆、鉛筆、毛筆等等。(這里抽象的說)如果我們要用到人的手寫字的時候,就必須提供給手很多中筆,可是每種筆的類型有各自不同,我們說筆有很多不同的屬性的功能。如果才能讓我們的手拿到任何一種筆都可以寫字呢,我們可以這樣做。將鋼筆、鉛筆、毛筆等等筆定義一種公共的「筆」的類型,讓我們的手在使用筆的時候,只需要知道要使用一個筆來寫字,而不需要關心使用什麼筆來寫。而決定給這只手用的筆的類型,就是你的事情了。
抽象成簡單的代碼:
interface Pen{}
class GangBi implements Pen{}
class MaoBi implements Pen{}
class QianBi implements Pen{}
class Human{
void usePen(Pen pen){}
}
這個概念超級抽象。不過,學習Spring框架可以快速的來理解這個概念。
『肆』 windows環境下Redis+Spring緩存實例
一、Redis了解
1.1、Redis介紹:
redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字元串)、list(鏈表)、set(集合)、zset(sorted set –有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁碟或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。
Redis資料庫完全在內存中,使用磁碟僅用於持久性。相比許多鍵值數據存儲,Redis擁有一套較為豐富的數據類型。Redis可以將數據復制到任意數量的從伺服器。
1.2、Redis優點:
(1)異常快速:Redis的速度非常快,每秒能執行約11萬集合,每秒約81000+條記錄。
(2)支持豐富的數據類型:Redis支持最大多數開發人員已經知道像列表,集合,有序集合,散列數據類型。這使得它非常容易解決各種各樣的問題,因為我們知道哪些問題是可以處理通過它的數據類型更好。
(3)操作都是原子性:所有Redis操作是原子的,這保證了如果兩個客戶端同時訪問的Redis伺服器將獲得更新後的值。
(4)多功能實用工具:Redis是一個多實用的工具,可以在多個用例如緩存,消息,隊列使用(Redis原生支持發布/訂閱),任何短暫的數據,應用程序,如Web應用程序會話,網頁命中計數等。
1.3、Redis缺點:
(1)單線程
(2)耗內存
二、64位windows下Redis安裝
Redis官方是不支持windows的,但是Microsoft Open Tech group 在 GitHub上開發了一個Win64的版本,下載地址:https://github.com/MSOpenTech/redis/releases。注意只支持64位哈。
小寶鴿是下載了Redis-x64-3.0.500.msi進行安裝。安裝過程中全部採取默認即可。
安裝完成之後可能已經幫你開啟了Redis對應的服務,博主的就是如此。查看資源管理如下,說明已經開啟:
已經開啟了對應服務的,我們讓它保持,下面例子需要用到。如果沒有開啟的.,我們命令開啟,進入Redis的安裝目錄(博主的是C:Program FilesRedis),然後如下命令開啟:
redis-server redis.windows.conf
OK,下面我們進行實例。
三、詳細實例
本工程採用的環境:Eclipse + maven + spring + junit
3.1、添加相關依賴(spring+junit+redis依賴),pom.xml:
4.0.0 com.luo redis_project 0.0.1-SNAPSHOT 3.2.8.RELEASE 4.10 org.springframework spring-core ${spring.version} org.springframework spring-webmvc ${spring.version} org.springframework spring-context ${spring.version} org.springframework spring-context-support ${spring.version} org.springframework spring-aop ${spring.version} org.springframework spring-aspects ${spring.version} org.springframework spring-tx ${spring.version} org.springframework spring-jdbc ${spring.version} org.springframework spring-web ${spring.version} junit junit ${junit.version} test org.springframework spring-test ${spring.version} test org.springframework.data spring-data-redis 1.6.1.RELEASE redis.clients jedis 2.7.3
3.2、spring配置文件application.xml:
<"1.0" encoding="UTF-8"> classpath:properties/*.properties
3.3、Redis配置參數,redis.properties:
#redis中心#綁定的主機地址redis.host=127.0.0.1#指定Redis監聽埠,默認埠為6379redis.port=6379#授權密碼(本例子沒有使用)redis.password=123456 #最大空閑數:空閑鏈接數大於maxIdle時,將進行回收redis.maxIdle=100 #最大連接數:能夠同時建立的「最大鏈接個數」redis.maxActive=300 #最大等待時間:單位msredis.maxWait=1000 #使用連接時,檢測連接是否成功 redis.testOnBorrow=true#當客戶端閑置多長時間後關閉連接,如果指定為0,表示關閉該功能redis.timeout=10000
3.4、添加介面及對應實現RedisTestService.Java和RedisTestServiceImpl.java:
package com.luo.service; public interface RedisTestService { public String getTimestamp(String param);}
package com.luo.service.impl; import org.springframework.stereotype.Service;import com.luo.service.RedisTestService; @Servicepublic class RedisTestServiceImpl implements RedisTestService { public String getTimestamp(String param) { Long timestamp = System.currentTimeMillis(); return timestamp.toString(); } }
3.5、本例採用spring aop切面方式進行緩存,配置已在上面spring配置文件中,對應實現為MethodCacheInterceptor.java:
package com.luo.redis.cache; import java.io.Serializable;import java.util.concurrent.TimeUnit;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations; public class MethodCacheInterceptor implements MethodInterceptor { private RedisTemplate redisTemplate; private Long defaultCacheExpireTime = 10l; // 緩存默認的過期時間,這里設置了10秒 public Object invoke(MethodInvocation invocation) throws Throwable { Object value = null; String targetName = invocation.getThis().getClass().getName(); String methodName = invocation.getMethod().getName(); Object[] arguments = invocation.getArguments(); String key = getCacheKey(targetName, methodName, arguments); try { // 判斷是否有緩存 if (exists(key)) { return getCache(key); } // 寫入緩存 value = invocation.proceed(); if (value != null) { final String tkey = key; final Object tvalue = value; new Thread(new Runnable() { public void run() { setCache(tkey, tvalue, defaultCacheExpireTime); } }).start(); } } catch (Exception e) { e.printStackTrace(); if (value == null) { return invocation.proceed(); } } return value; } /** * 創建緩存key * * @param targetName * @param methodName * @param arguments */ private String getCacheKey(String targetName, String methodName, Object[] arguments) { StringBuffer sbu = new StringBuffer(); sbu.append(targetName).append("_").append(methodName); if ((arguments != null) && (arguments.length != 0)) { for (int i = 0; i < arguments.length; i++) { sbu.append("_").append(arguments[i]); } } return sbu.toString(); } /** * 判斷緩存中是否有對應的value * * @param key * @return */ public boolean exists(final String key) { return redisTemplate.hasKey(key); } /** * 讀取緩存 * * @param key * @return */ public Object getCache(final String key) { Object result = null; ValueOperations operations = redisTemplate .opsForValue(); result = operations.get(key); return result; } /** * 寫入緩存 * * @param key * @param value * @return */ public boolean setCache(final String key, Object value, Long expireTime) { boolean result = false; try { ValueOperations operations = redisTemplate .opsForValue(); operations.set(key, value); redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); result = true; } catch (Exception e) { e.printStackTrace(); } return result; } public void setRedisTemplate( RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; }}
3.6、單元測試相關類:
package com.luo.baseTest; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; //指定bean注入的配置文件 @ContextConfiguration(locations = { "classpath:application.xml" }) //使用標準的JUnit @RunWith注釋來告訴JUnit使用Spring TestRunner @RunWith(SpringJUnit4ClassRunner.class) public class SpringTestCase extends { }
package com.luo.service; import org.junit.Test;import org.springframework.beans.factory.annotation.Autowired; import com.luo.baseTest.SpringTestCase; public class RedisTestServiceTest extends SpringTestCase { @Autowired private RedisTestService redisTestService; @Test public void getTimestampTest() throws InterruptedException{ System.out.println("第一次調用:" + redisTestService.getTimestamp("param")); Thread.sleep(2000); System.out.println("2秒之後調用:" + redisTestService.getTimestamp("param")); Thread.sleep(11000); System.out.println("再過11秒之後調用:" + redisTestService.getTimestamp("param")); } }
3.7、運行結果:
四、源碼下載:redis-project().rar
以上就是本文的全部內容,希望對大家的學習有所幫助。
『伍』 springboot 面向切面編程之使用自定義註解
我們知道使用@Pointcut註解定義切點,它的value屬性可以是 切點表達式 或者 註解的全限定名 ;若使用註解的方式,直接在目標切入點方法上加上自定義註解即可納入AOP的管理
在創建自定義註解時有看到三個註解,分別了解它們的作用
我們先來看看這個枚舉類java.lang.annotation.ElementType就是定義註解使用的地方。比如 @Target(ElementType.METHOD) 就是只能用在方法上了。不過可以同時指定多個ElementType的屬性來達到既可以用在方法上也可以用在類上的目的: @Target({ElementType.TYPE, ElementType.METHOD})
Documented註解表明這個注釋是由 javadoc記錄的。 如果一個類型聲明被注釋了文檔化,它的注釋成為公共API的一部分。
再來看這個枚舉類 java.lang.annotation.RetentionPolicy。該類主要功能是定義註解的 生命周期
創建註解類TestAnnotation。裡面有一個name參數,默認是no;沒錯,該註解只能用在方法上,不能用在類、介面;而且是運行時類型的
在目標方法上使用註解
創建切面類
最後重啟工程,訪問 http://localhost:8080/test/aop/testAop1 和 http://localhost:8080/test/aop/testAop2
『陸』 aop原理和機制
在軟體業,AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預編譯方式和運行期間動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生范型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
中文名
面向切面編程
外文名
Aspect Oriented Programming
簡稱
AOP
屬性
軟體開發技術
衍生范型
函數式編程
快速
導航
AOP/OOP應用舉例應用范圍實現項目作用實現工業化應用小結
名稱含義
Aspect Oriented Programming(AOP)是較為熱門的一個話題。AOP,國內大致譯作「面向切面編程」。
「面向切面編程」,這樣的名字並不是非常容易理解,且容易產生一些誤導。有些人認為「OOP/OOD11即將落伍,AOP是新一代軟體開發方式」。顯然,發言者並沒有理解AOP的含義。Aspect,的確是「方面」的意思。不過,漢語傳統語義中的「方面」,大多數情況下指的是一件事情的不同維度、或者說不同角度上的特性,比如我們常說:「這件事情要從幾個方面來看待」,往往意思是:需要從不同的角度來看待同一個事物。這里的「方面」,指的是事物的外在特性在不同觀察角度下的體現。而在AOP中,Aspect的含義,可能更多的理解為「切面」比較合適。
『柒』 誰能解釋一下java面向切面編程的思想 以及具體的使用方式
面向切面編程(AOP),就是關注程序運行的過程,切面就是要把方法切開,分別執行前,執行中,執行後(可能更細化)等多個步驟,分別針對這三個階段進行處理。以獲得邏輯過程中各部分之間低耦合性的隔離效果。
具體使用場景:
事務管理:我們在操作資料庫的時候需要在操作前打開事務,結束後提交事務(或回滾事務),按往常的編碼方式,我們會在每個方法前、後都添加一些事務操作的重復的代碼,使得每個類都與事務操作相耦合;而使用了AOP,代碼上看上去就是直接操作的資料庫,而我們通過某種機制,可讓代碼在你不察覺的情況下進行了事務開啟和提交(或回滾),事實上Spring就提供了這種事務機制。
差不多的場景還有日誌的記錄
『捌』 PHP怎麼實現面向切面編程
下面是向切面式組件源碼,是根據AOP的思路設計的:
<?php
if (function_exists('__autoload')) {
trigger_error("Extension: It looks like your code is using an __autoload() function. Extension uses spl_autoload_register() which will bypass your __autoload() function and may break autoloading.", E_USER_WARNING);}
spl_autoload_register(array('ExtensionFactory', 'autoload'));class ExtensionFactory {
private static $extFamily = null;
private static $_classes = array(
'Extension' => '/Extension.php',
'ExtensionFamily' => '/ExtensionFamily.php'
);
/**
* Class autoloader. This method is provided to be invoked within an* __autoload() magic method.
* @param string $className The name of the class to load.
*/
public static function autoload() {
foreach(self::$_classes as $v){
require_once dirname(__FILE__) . $v;
}
}
/**
* 必須先調用此方法來實例化擴展族,才能調用addExtension\removeExtension等* @return ExtensionFamily
*/
public static function createExtension(){self::$extFamily = new ExtensionFamily();return self::$extFamily;
}
public static function removeExtension($extName){if(is_null(self::$extFamily)){
throw new Exception("Please createExtension first");return false;
}else{
unset(self::$extFamily->_extensionArray[$extName]);}
}
public static function addExtension($extName, Extension $ext){if(is_null(self::$extFamily)){
throw new Exception("Please createExtension first");return false;
}else{
self::$extFamily->_extensionArray[$extName] = $ext;}
}
public static function removeAllExtension(){if(is_null(self::$extFamily)){
throw new Exception("Please createExtension first");return false;
}else{
foreach(self::$extFamily->_extensionArray as $extName=>$ext){unset(self::$extFamily->_extensionArray[$extName]);}
}
}
}
<?php
if (function_exists('__autoload')) {
trigger_error("Extension: It looks like your code is using an __autoload() function. Extension uses spl_autoload_register() which will bypass your __autoload() function and may break autoloading.", E_USER_WARNING);}
spl_autoload_register(array('ExtensionFactory', 'autoload'));class ExtensionFactory {
private static $extFamily = null;
private static $_classes = array(
'Extension' => '/Extension.php',
'ExtensionFamily' => '/ExtensionFamily.php'
);
/**
* Class autoloader. This method is provided to be invoked within an* __autoload() magic method.
* @param string $className The name of the class to load.
*/
public static function autoload() {
foreach(self::$_classes as $v){
require_once dirname(__FILE__) . $v;
}
}
/**
* 必須先調用此方法來實例化擴展族,才能調用addExtension\removeExtension等* @return ExtensionFamily
*/
public static function createExtension(){self::$extFamily = new ExtensionFamily();return self::$extFamily;
}
public static function removeExtension($extName){if(is_null(self::$extFamily)){
throw new Exception("Please createExtension first");return false;
}else{
unset(self::$extFamily->_extensionArray[$extName]);}
}
public static function addExtension($extName, Extension $ext){if(is_null(self::$extFamily)){
throw new Exception("Please createExtension first");return false;
}else{
self::$extFamily->_extensionArray[$extName] = $ext;}
}
public static function removeAllExtension(){if(is_null(self::$extFamily)){
throw new Exception("Please createExtension first");return false;
}else{
foreach(self::$extFamily->_extensionArray as $extName=>$ext){unset(self::$extFamily->_extensionArray[$extName]);}
}
}
}
<?php
/**
* 擴展家族
*
* @author Mr.Jin
*/
class ExtensionFamily implements Extension{public $_extensionArray = array();
/**
*
* @param type $extName 擴展名
* @param Extension $ext 實現Extension的對象*/
public function addExtension($extName, Extension $ext){$this->_extensionArray[$extName] = $ext;
}
public function beforeAppend(&$params){
foreach($this->_extensionArray as $ext){
$ext->beforeAppend($params);
}
}
public function afterAppend(&$params) {
foreach($this->_extensionArray as $ext){
$ext->afterAppend($params);
}
}
}
?>
<?php
/**
* 擴展家族
*
* @author Mr.Jin
*/
class ExtensionFamily implements Extension{public $_extensionArray = array();
/**
*
* @param type $extName 擴展名
* @param Extension $ext 實現Extension的對象*/
public function addExtension($extName, Extension $ext){$this->_extensionArray[$extName] = $ext;
}
public function beforeAppend(&$params){
foreach($this->_extensionArray as $ext){
$ext->beforeAppend($params);
}
}
public function afterAppend(&$params) {
foreach($this->_extensionArray as $ext){
$ext->afterAppend($params);
}
}
}
?>
<?php
/**
* 擴展介面
*
* @author Mr.Jin
*/
interface Extension {
public function beforeAppend(&$params);
public function afterAppend(&$params);
}
?>
<?php
/**
* 擴展介面
*
* @author Mr.Jin
*/
interface Extension {
public function beforeAppend(&$params);
public function afterAppend(&$params);
}
?>
以上三個文件實現了簡單的AOP組件。
下面是Demo:
<?php
/**
* 自定義Extension
* 用戶積分Extension
* 根據用戶是否登錄,決定此次消費是否記錄用戶積分*
* @author Mr.Jin
*/
class ExampleExtension implements Extension {public $check=false;
public function beforeAppend(&$isLogin) {if($isLogin){
$this->check = true;
}
}
public function afterAppend(&$pointer) {
if($this->check){
//add pointer
}else{
echo '未登錄用戶,積分不錄入';
return;
}
}
}
?>
<?php
/**
* 自定義Extension
* 用戶積分Extension
* 根據用戶是否登錄,決定此次消費是否記錄用戶積分*
* @author Mr.Jin
*/
class ExampleExtension implements Extension {public $check=false;
public function beforeAppend(&$isLogin) {if($isLogin){
$this->check = true;
}
}
public function afterAppend(&$pointer) {
if($this->check){
//add pointer
}else{
echo '未登錄用戶,積分不錄入';
return;
}
}
}
?>
demo.php
<?php
require_once('ExtensionFactory.php');//導入組件本身require_once('ExampleExtension.php');//導入擴展$ext = ExtensionFactory::createExtension();ExtensionFactory::addExtension('example', new ExampleExtension());//積分錄入功能/*
* 按照需求的變化,可以增加相應的Extension.
* eg.
* 新需求:新增會員類型,根據不同類型,進行價格優惠。
* 實現思路:
* 一、建立卡號類型工廠
* 二、建立SeniorMemberExtension、PuTongMeberExtension.
* 三、工廠方法根據會員類型addExtension
*/
$isLogin = false; //假設用戶未登錄
$ext->beforeAppend($isLogin);
/**
* 面向切面編程,最重要一點是:必須先分析出整個業務處理中,哪個才是重點。
* 這里的重點是訂單的入庫。
* 在訂單入庫之前可能業務邏輯不斷增加,例如:登錄驗證、卡上余額驗證等* 在訂單入庫之後:積分處理、訂單監控等
*/
echo "此處是主要業務邏輯:訂單入庫\r\n";
$pointer = 100;
$ext->afterAppend($pointer);
<?php
require_once('ExtensionFactory.php');//導入組件本身require_once('ExampleExtension.php');//導入擴展$ext = ExtensionFactory::createExtension();ExtensionFactory::addExtension('example', new ExampleExtension());//積分錄入功能/*
* 按照需求的變化,可以增加相應的Extension.
* eg.
* 新需求:新增會員類型,根據不同類型,進行價格優惠。
* 實現思路:
* 一、建立卡號類型工廠
* 二、建立SeniorMemberExtension、PuTongMeberExtension.
* 三、工廠方法根據會員類型addExtension
*/
$isLogin = false; //假設用戶未登錄
$ext->beforeAppend($isLogin);
/**
* 面向切面編程,最重要一點是:必須先分析出整個業務處理中,哪個才是重點。
* 這里的重點是訂單的入庫。
* 在訂單入庫之前可能業務邏輯不斷增加,例如:登錄驗證、卡上余額驗證等* 在訂單入庫之後:積分處理、訂單監控等
*/
echo "此處是主要業務邏輯:訂單入庫\r\n";
$pointer = 100;
$ext->afterAppend($pointer);