当前位置:首页 » 硬盘大全 » 面向切面增加缓存
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

面向切面增加缓存

发布时间: 2022-12-19 21:50:44

‘壹’ 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),就是关注程序运行的过程,切面就是要把方法切开,分别执行前,执行中,执行后(可能更细化)等多个步骤,分别针对这三个阶段进行处理。以获得逻辑过程中各部分之间低耦合性的隔离效果。

具体使用场景:

  1. 事务管理:我们在操作数据库的时候需要在操作前打开事务,结束后提交事务(或回滚事务),按往常的编码方式,我们会在每个方法前、后都添加一些事务操作的重复的代码,使得每个类都与事务操作相耦合;而使用了AOP,代码上看上去就是直接操作的数据库,而我们通过某种机制,可让代码在你不察觉的情况下进行了事务开启和提交(或回滚),事实上Spring就提供了这种事务机制。

  2. 差不多的场景还有日志的记录

‘捌’ 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);