AOP
/**
凡是注解了RequestMapping的方法都被拦截
*/
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
private void webPointcut() {
}
/**
拦截web层异常,记录异常日志,并返回友好信息到前端 方法只拦截Exception
将未做处理的异常统一进行处理
*/
@AfterThrowing(pointcut = “webPointcut()”, throwing = “e”)
public void handleThrowing(Exception e) {
logger.error(JSON.toJSONString(e.getStackTrace()));
//通过response和writer将信息输出到浏览器
}
IOC、DI
特点
序列化
IO 一对一(一个线程对应一个连接)
NIO 一对多(一个线程对应多个连接),非阻塞IO
使用
public class NettyServer {
public static void main(String[] args) {
ServerBootstrap serverBootstrap = new ServerBootstrap();
NioEventLoopGroup boos = new NioEventLoopGroup();
NioEventLoopGroup worker = new NioEventLoopGroup();
serverBootstrap
.group(boos, worker) // 创建分组
.channel(NioServerSocketChannel.class) // 创建频道
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(NioSocketChannel ch) {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new SimpleChannelInboundHandler() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
System.out.println(msg);
}
});
}
})
.bind(8000); // 监听8000端口
}
}
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
Bootstrap bootstrap = new Bootstrap();
NioEventLoopGroup group = new NioEventLoopGroup();
bootstrap
.group(group) //组信息
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(Channel ch) {
ch.pipeline().addLast(new StringEncoder());
}
});
//监听url和端口
Channel channel = bootstrap.connect("127.0.0.1", 8000).channel();
while (true) {
channel.writeAndFlush(new Date() + ": hello world!");
Thread.sleep(2000);
}
}
Nginx
MQ(Kafka) kafka常见问题
producer生产:
@Autowired
private KafkaTemplate kafkaTemplate;
@RequestMapping("/send")
public String send(String msg) {
kafkaTemplate.send("group-id", msg);
return "success";
}
consumer消费
// 如果是单消费组,这里的group-id就是topicName
@KafkaListener(topics = "group-id")
public void listen(ConsumerRecord, ?> record) throws Exception {
System.out.printf("topic = %s, offset = %d, value = %s \n"
, record.topic(), record.offset(), record.value());
}
Zookeeper 常见功能
=3台服务器,投票选举
Mysql
Nosql(Redis、MongoDB等)
Elasticsearch与Hbase的分析
Elasticsearch
特点
场景
日志
持久化
优化
基础概念
API基本格式:http://
put请求:http://\:\/<索引>
{
"settings":{
"number_of_shards": 3, // 分片
"number_of_replicas": 1 // 备份
},
"mappings":{ // 索引结构
"man":{ // 类型
"properties":{ // 文档
"name":{
"type":"text"
},
"country":{
"type": "keyword"
},
Hbase(Hadoop database)
抽象、封装、继承、多态、组合
io
泛型
数据结构
多线程
private static ExecutorService executorService;
public static ExecutorService getExecutorService(String groupName) {
synchronized (ExecutorFactory.class) {
if (executorService == null) {
executorService = new ThreadPoolExecutor(4, 8,
Long.MAX_VALUE, TimeUnit.NANOSECONDS, new LinkedBlockingQueue<>(1024),
// Executors.defaultThreadFactory(), // 默认工厂
new UserThreadFactory(groupName), // 自定义工厂,可以console线程组和一些上下文参数
new ThreadPoolExecutor.CallerRunsPolicy());
}
}
return executorService;
}
// int corePoolSize, //常驻核心数,0:直接销毁;需要合理分配,太大浪费资源,太小频会繁销毁创建
// int maximumPoolSize, //最大数, >=1 超过会进入缓存队列
// long keepAliveTime, // 连接最大时间,这里使用了最长时间
// TimeUnit unit, // 时间格式,一般使用秒
// BlockingQueue workQueue, // 等待中的任务队列,超过则执行抛弃策略;队列有三种策略,不过阿里云推荐这样,所以有其他需要上网再查
// 该队列为单向链表,使用锁来控制入队和出队的原子性,是一个生产消费模型队列
// ThreadFactory threadFactory, // 创建线程工程,线程池命名是通过给这个工厂增加组命名来实现的
// RejectedExecutionHandler handler // 拒绝策略,超过缓存队列长度以后执行,阿里建议一般跳转固定页面并将数据记数据库or日志后期削峰填谷再处理
//抛弃策略
// ThreadPoolExecutor.AbortPolicy() 抛出java.util.concurrent.RejectedExecutionException异常
// ThreadPoolExecutor.CallerRunsPolicy() 重试添加当前的任务,他会自动重复调用execute()方法
// ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务
// ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务
// 不过默认的抛弃策略和线程工厂功能简单,一般不满足使用,实现自己的更合适,实现见
```
* 使用
```
while(线程池数量){
Future future = executorService.submit(() -> {
......
})
}
boolean isDone = false;
while (!isDone){
if(future.isDone()) {
// System.out.println(future.get());
isDone = true;
} else {
System.out.println(false);
Thread.sleep(50);
}
}
service.shutdown();
```
反射
动态代理,框架等底层都是通过该方法进行切面编程的:eg:HttpServlet的dopost方法调用
method:
private void testInvocation2(){
PersonServer server = new PersonProxy().getPersonProxy();
server.login();
server.submit();
}
// 代理类
public class PersonProxy {
// 业务接口
private PersonServer server = new PersonServerImp();
public PersonServer getPersonProxy() {
// 返回一个代理
return (PersonServer) Proxy.newProxyInstance(
server.getClass().getClassLoader()
, server.getClass().getInterfaces()
, (proxy, method, args) -> {
if (method.getName().equals("login")) {
// 前置业务
System.out.println("login_begin");
// 主业务执行
Object object = method.invoke(server, args);
// 后置业务
System.out.println("login_end");
// 返回执行结果
return object;
} else if (method.getName().equals("submit")) {
// 其他方法
return method.invoke(server, args);
}
return null;
});
}
}
// (proxy, method, args) -> {}的原文
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
}
}
异常
测试
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = xxxApplication.class)
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webContext;
@Before
public void before() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webContext).build();
}
@After
public void after() throws Exception {
}
@Test
public void testIndexFail() throws Exception {
String responseString = mockMvc
.perform(get("/api/***")
.accept(MediaType.APPLICATION_JSON_UTF8)
)
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
assertNotNull(responseString);
JSONObject json = JSONObject.fromObject(responseString);
assertEquals(json.getString("code").toString(), "1");
assertEquals(json.getString("msg").toString(), TrainConstants.ErrorMsg.PARAMS_ERROR);
}
日志
运行 ./xx.sh,如果不用./则会去path里面找路径
变量
基础
字符串
数组
传递参数
echo "执行的文件名:$0";
echo "第一个参数为:$1";
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
命令-关系与逻辑
命令-文件测试运算符
命令-其他
read 获取console的输入
echo
printf,同c语言
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
# %s %c %d %f都是格式替代符;-10:宽度;-4.2f:保留小数等
printf "%s %s\n" "参数一" "参数二"
# 参数一 参数二
printf "%s %s %s\n" "参数一" "参数二"
# 参数一 参数二
printf "%s\n" "参数一" "参数二" "参数三"
# 参数一
# 参数二
# 参数三
test eg:if test $num1 = $num2
流程控制
read item
case "$item" in
1|z|\*)
echo "case 1"
;;
*)
echo "default"
;;
esac
函数,注意参数当n>=10时,需要使用${n}来获取参数
function name () {
echo "name函数->$1" #a
}
name a b c d
输入/重定向