发表于: 2020-07-03 22:15:07

1 1682


今天完成的事情:

完善昨天的代码使用SpringAOP来编写一个日志类记录各方法耗费的时间

昨天使用的xml配置,今天学习一下用注解的方式来使用AOP

package com.jnshu.util;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;


@Component("logger")
@Aspect//表示当前类是一个切面
public class LoggerAop {

@Pointcut("execution( * com.jnshu.service.StudentServiceImpl.selectStudent())")
private void pt1(){}

private static final Logger logger = Logger.getLogger(LoggerAop.class);
   //环绕通知
   @Around("pt1()")
public Object printLog(ProceedingJoinPoint pjp){
Object rtValue = null;
       try{
Object[] args = pjp.getArgs();
           Long start = System.currentTimeMillis();
           rtValue = pjp.proceed();
           Long end = System.currentTimeMillis();
           Long taketime = end - start;
           logger.info("请求总耗时:" + taketime + "毫秒");
           return rtValue;
       }catch (Throwable t){
throw new RuntimeException(t);
       }
}

}

然后配置文件里加上:

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

再修改一下,加入识别当前方法名,并且将controller层也配置切面:

package com.jnshu.util;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;


@Component("logger")
@Aspect//表示当前类是一个切面
public class LoggerAop {

@Pointcut("execution( * com.jnshu.service.*.*(..))||execution( * com.jnshu.controller.*.*(..))")
private void pt1(){}

private static final Logger logger = Logger.getLogger(LoggerAop.class);
   //环绕通知
   @Around("pt1()")
public Object printLog(ProceedingJoinPoint pjp){
Object rtValue = null;
       String methodName = pjp.getSignature().getName();
       try{
Object[] args = pjp.getArgs();
           Long start = System.currentTimeMillis();
           rtValue = pjp.proceed();
           Long end = System.currentTimeMillis();
           Long taketime = end - start;
           logger.info(methodName + "请求总耗时:" + taketime + "毫秒");
           return rtValue;
       }catch (Throwable t){
throw new RuntimeException(t);
       }
}

}


测试一下效果:


可以看到各个方法所耗费的时间了,发现消耗的时间主要再selectStudent方法。


学习Memcache.

一、memcache概述

1、memcache就是一个数据库、但是数据存在内存中。常用来做缓存服务器、将从数据库查询的数据缓存起来,减少数据库查询、加快查询速度。

2、明确使用场景:缓存服务器

3、适合存储的数据:

①访问比较频繁的数据,安全性差的数据,丢失无所谓的数据。

②数据更新,比较频繁的数据,比如用户的在线状态。

③数据的单个键值不能太大,不要超过1Mb数据。


什么是Memcache?

Memcache集群环境下缓存解决方案

Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。简单的说就是将数据调用到内存中,然后从内存中读取,从而大大提高读取速度。  

Memcache是danga的一个项目,最早是LiveJournal 服务的,最初为了加速 LiveJournal 访问速度而开发的,后来被很多大型的网站采用。  

Memcached是以守护程序方式运行于一个或多个服务器中,随时会接收客户端的连接和操作

 

为什么会有Memcache和memcached两种名称?

其实Memcache是这个项目的名称,而memcached是它服务器端的主程序文件名。一个是项目名称,一个是主程序文件名.

Memcached是高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。Memcached由Danga Interactive开发,用于提升LiveJournal.com访问速度的。LJ每秒动态页面访问量几千次,用户700万。Memcached将数据库负载大幅度降低,更好的分配资源,更快速访问。


昨天已经安装了Memcached

以管理员身份运行cmd,输入memcached -d start启动

输入telnet 127.0.0.1 11211链接Memcached,进入以下界面:


输入set username 0 120 5

作用:set命令用于向memcache存储一对键值对数据

username[key] 0[是否压缩] 120[存活时长] 5[字符长度]

如果字符长度不符会报错:

如果符合则:


输入get username来查看key:


add和set类似,不过如果key已经存在,使用add不会更新并提示NOT_STORED,而使用set会覆盖之前的key

delete key 可以删除key

flush_all 可以删除memcached中所有的key及value

incr 可以对key存在的value进行相加操作

decr 可以对key存在的value进行相减操作

stats 返回memcached统计信息(比如set、get总数,连接数等....)

1、cmd_get:执行get请求次数

1、cmd_set:执行set请求次数

3、get_misses:get指令未命中次数

4、get_hits:get指令命中次数

5、curr_connections:当前连接数


整合memcached:

Memcached Client目前有3种: 

Memcached Client for Java

SpyMemcached

XMemcached


这三种Client一直存在各种争议: 

Memcached Client for Java 比 SpyMemcached更稳定、更早、更广泛;

SpyMemcached 比 Memcached Client for Java更高效;

XMemcached 比 SpyMemcache并发效果更好。

 

XMemcached特性: 

高性能

支持完整的memcached文本协议,二进制协议。

支持JMX,可以通过MBean调整性能参数、动态添加/移除server、查看统计等。

支持客户端统计

支持memcached节点的动态增减。

支持memcached分布:余数分布和一致性哈希分布。

更多的性能调整选项。

此外,XMemcached更容易与Spring集成。


Spring整合Memcached:

导入依赖:

<!-- https://mvnrepository.com/artifact/com.whalin/Memcached-Java-Client -->
<dependency>
 <groupId>com.whalin</groupId>
 <artifactId>Memcached-Java-Client</artifactId>
 <version>3.0.2</version>
</dependency>


创建配置文件:memcached.xml

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="memCachedPool" class= "com.whalin.MemCached.SockIOPool"
   factory-method="getInstance" init-method="initialize"
   lazy-init="false" destroy-method="shutDown">
   <!-- 构造函数 -->
   <constructor-arg value="memCachedPool"/>

   <!-- 可以设置多个memcachePool服务器 -->
   <property name="servers">
       <list>
           <value>127.0.0.1:11211</value>
       </list>
   </property>

   <!-- 每台服务器的初始连接 -->
   <property name="initConn" value="10"/>

   <!-- 每台服务器的最小连接 -->
   <property name="minConn" value="5"/>

   <!-- 每台服务器的最大连接数 -->
   <property name="maxConn" value="250"/>

   <!-- 主线程睡眠时间 -->
   <property name="maintSleep" value="30"/>

   <!-- Tcp/Socket 的参数, 如果是true在写数据时不会缓冲, 会立即发出 -->
   <property name="nagle" value="false"/>

   <!-- 连接超时/阻塞读取时间的超时时间 -->
   <property name="socketTO" value="3000"/>
   </bean>

   <bean id="memCachedClient" class= "com.whalin.MemCached.MemCachedClient" lazy-init="false">
   <constructor-arg value="memCachedPool"/>
   </bean>
</beans>

同时在applicationContext.xml中配置:

<import resource="memcached.xml"/>


修改业务层:

package com.jnshu.service;

import com.jnshu.dao.StudentMapper;
import com.jnshu.pojo.Student;
import com.whalin.MemCached.MemCachedClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StudentServiceImpl implements StudentService {

@Autowired private StudentMapper studentMapper;

   @Autowired
   private MemCachedClient memCachedClient;

   @Override
   public int deleteByPrimaryKey(Long id) {
int i = studentMapper.deleteByPrimaryKey(id);
       if(i>0){
//同时删除缓存
           System.out.println("删除缓存。。。" + id);
           memCachedClient.delete("student" + id);
       }
return i;
   }

@Override
   public int insert(Student record) {
int i = studentMapper.insert(record);
       if(i>0){
System.out.println("存入缓存" + record);
           memCachedClient.add("student" + record.getId(),record);
       }
return i;
   }

@Override
   public Student selectByPrimaryKey(Long id) {
//先查询缓存中是否存在,若存在则直接从缓存中取
       Student student = (Student)memCachedClient.get("student"+id);
       if(student != null){
System.out.println("从缓存中查询");
       }else{
//若缓存中不存在,则从数据库中查询,并存入缓存
           System.out.println("从数据库中查询");
           student = studentMapper.selectByPrimaryKey(id);
           memCachedClient.add("student"+ id ,student);
       }
return student;
   }

@Override
   public List<Student> selectStudent() {
List<Student> list = (List<Student>)memCachedClient.get("AllStudent");
       if(list != null){
System.out.println("从缓存中查询。。。");
       }else{
System.out.println("从数据库中查询。。。");
           list = studentMapper.selectStudent();
           memCachedClient.add("AllStudent",list);
       }
return studentMapper.selectStudent();
   }

@Override
   public int selectByLearning() {
return studentMapper.selectByLearning();
   }

@Override
   public int selectByWorking() {
return studentMapper.selectByWorking();
   }

@Override
   public int updateByPrimaryKeySelective(Student record) {
int i = studentMapper.updateByPrimaryKeySelective(record);
       if(i>0){
memCachedClient.replace("student"+record.getId(),record);
       }
return i;
   }
}

测试一下:

查询速度显著提升!


使用JMeter进行压力测试:

线程数设500都很快:

后面直接加到2000站点就挂了。。。


收获:完成了使用SpingAOP编写日志模块,初步整合Memcached。

碰到的问题:现在站点挂了进不去了,重启tomcat也没用。。。

明天计划的事情:

继续任务六。


返回列表 返回列表
评论

    分享到