适用于类似消息发布,监听
1、创建event类继承org.springframework.context.ApplicationEvent
2、创建listener类实现接口org.springframework.context.ApplicationListener传入泛形为上面定义的event,并声明为组件
3、applicationContext.publish(new event),使所订阅者都可以收到事件执行
4、未来扩展方式:只需要新增实现event的listener即可自动订阅
public class ImsgEvent extends ApplicationEvent{
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public ImsgEvent(Object source) {
super(source);
}
}
package com.example.springBootTest.eventTest;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class WeChatListener implements ApplicationListener<ImsgEvent> {
@Override
public void onApplicationEvent(@NotNull ImsgEvent event) {
System.out.println("微信发送成功");
System.out.println(event.getSource().toString());
}
}
package com.example.springBootTest.eventTest;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MsgListener implements ApplicationListener<ImsgEvent> {
@Override
public void onApplicationEvent(ImsgEvent event) {
System.out.println("短信发送成功");
}
}
package com.example.springBootTest.eventTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;
@Service
public class orderServce {
public orderServce(ApplicationContext ctx ) {
System.out.println("订单已生成");
String msg = "order created";
ctx.publishEvent(new ImsgEvent(msg));
}
}
2020-08-28 10:37:40.441 INFO 4320 --- [ main]
订单已生成
短信发送成功
微信发送成功
order created
2020-08-28 10:37:40.628 INFO 4320 --- [ main]
适用于类似区分不同用户执行不同取价,用户身份未来可能会新增的情况
1、编写strategy接口
2、创建实现strategy接口的具体执行类比如*strategy{type:},@server 注入到bean中
3、通过构造注入的方式将所有strategy实现类获取,根据type封装到map中
4、通过map.get(Type)获取到具体实现的strategy,执行对应方法获取价格
5、未来扩展方式:只需要实现对应的strategy接口,书名类中type类型即可
package com.example.springBootTest.testStrategy;
public interface IpriceStrategy {
double calDisCount(double price);
String getuserTpye();
}
package com.example.springBootTest.testStrategy;
import org.springframework.stereotype.Service;
@Service
public class NormalStrategyService implements IpriceStrategy{
@Override
public double calDisCount(double price) {
return price;
}
@Override
public String getuserTpye() {
return "normal";
}
}
package com.example.springBootTest.testStrategy;
import org.springframework.stereotype.Service;
@Service
public class VippriceStrategyService implements IpriceStrategy {
@Override
public double calDisCount(double price) {
return price*0.9;
}
@Override
public String getuserTpye() {
return "vip";
}
}
package com.example.springBootTest.testStrategy;
import org.springframework.stereotype.Service;
@Service
public class VVippriceStrategyService implements IpriceStrategy {
@Override
public double calDisCount(double price) {
return price*0.8;
}
@Override
public String getuserTpye() {
return "vvip";
}
}
package com.example.springBootTest.testStrategy;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class CalPriceService {
Map<String,IpriceStrategy> map ;
public CalPriceService(List<IpriceStrategy> list) {
System.out.println("calPriceService");
Map<String,IpriceStrategy> map = new HashMap<String,IpriceStrategy>();
for (IpriceStrategy ipriceStrategy : list) {
map.put(ipriceStrategy.getuserTpye(),ipriceStrategy);
}
System.out.println(map.get("vip").calDisCount(100));
System.out.println( map.get("vvip").calDisCount(100));
System.out.println(map.get("normal").calDisCount(100));
}
}
calPriceService
90.0
80.0
100.0
1、方法中定义方法,实现使用虚类
2、使用时直接重写虚类代码就可以
1、引入AOP依赖
2、编辑AOP切面类,设置切面方法和实现方法
3、主类开启aop
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
package com.example.springBootTest.testAOP;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class testAOPAspect {
@Around("@annotation(aopAnnotion)")
public Object testAop(ProceedingJoinPoint joinPoint) {
System.out.println("我是通过around在你之前执行");
Object proceed = new Object();
try {
Object[] args = joinPoint.getArgs();
System.out.println("我知道了你的参数"+args[0].toString());
proceed = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("我是通过around在你之后执行");
return proceed;
}
}
@EnableAspectJAutoProxy//开启AOP
package com.example.springBootTest.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringApplicationContextUtil.applicationContext == null) {
SpringApplicationContextUtil.applicationContext = applicationContext;
}
}
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
package com.example.springBootTest;
import com.example.springBootTest.testAOP.AopTestServer;
import com.example.springBootTest.util.SpringApplicationContextUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy//开启AOP
public class SpringBootTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootTestApplication.class, args);
ApplicationContext context = SpringApplicationContextUtil.getApplicationContext();
AopTestServer bean = context.getBean(AopTestServer.class);
bean.doServer("我是传入参数");
}
}
我被构造了
我是通过around在你之前执行
我知道了你的参数我是传入参数
我被执行了我是传入参数
我是通过around在你之后执行
示例:
package com.example.springBootTest.testAOP;
import org.springframework.stereotype.Service;
@Service
public class AopTestServer {
public AopTestServer() {
System.out.println("我被构造了");
doServer("我是构造中被调用时传入的参数");
}
@aopAnnotion
public void doServer(String msg) {
System.out.println("我被执行了,传入参数是:"+msg);
}
}
结果:
我被构造了
我被执行了,传入参数是:我是构造中被调用时传入的参数
2020-08-28 19:37:22.819 INFO 5796 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-08-28 19:37:22.967 INFO 5796 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-08-28 19:37:22.975 INFO 5796 --- [ main] c.e.s.SpringBootTestApplication : Started SpringBootTestApplication in 1.961 seconds (JVM running for 2.757)
我是通过around在你之前执行
我知道了你的参数我是传入参数
我被执行了,传入参数是:我是传入参数
我是通过around在你之后执行
callable和runable的区别
1、callable有返回值
2、callable会抛出异常
3、结合futureTask使用,futureTask中run方法里面会调用callable.call
4、futureTask的get()方法中,会停滞当前线程,直到有返回值结果返回
package com.example.springBootTest.threadTest.service;
import org.springframework.stereotype.Service;
import java.util.Random;
@Service
public class threadTestService {
public String getUserPic() throws InterruptedException {
Thread.sleep(1000);
return "照片";
}
public String getUserName() throws InterruptedException {
Thread.sleep(1500);
return "张大大";
}
}
@Autowired
threadTestService threadTestService;
@Test
void contextLoads() {
long timeInMillis = System.currentTimeMillis();
try {
String userName = threadTestService.getUserName();
System.out.println("i got userName in " + String.valueOf(System.currentTimeMillis()-timeInMillis) + "ms,userName is "+userName);
String userPic = threadTestService.getUserPic();
System.out.println("i got userName in " + String.valueOf(System.currentTimeMillis()-timeInMillis) + "ms,userPic is "+userPic);
System.out.println("返回值是"+userName+userPic);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
i got userName in 1501ms,userName is 张大大
i got userName in 2502ms,userPic is 照片
返回值是张大大照片
说明前后串联执行,总共耗时为加法
@Test
void contextLoadsTread() {
long timeInMillis = System.currentTimeMillis();
AtomicReference<String> userName =new AtomicReference<>();
AtomicReference<String> userPic = new AtomicReference<>();
new Thread(()-> {
try {
userName.set(threadTestService.getUserName());
System.out.println("i got userName in " + String.valueOf(System.currentTimeMillis()-timeInMillis) + "ms,userName is "+userName);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
userPic.set(threadTestService.getUserPic());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("i got userName in " + String.valueOf(System.currentTimeMillis()-timeInMillis) + "ms,userPic is "+userPic);
}).start();
// try {
// Thread.sleep(5000);
// } catch ( InterruptedException e ) {
// e.printStackTrace();
// }
System.out.println("返回值是"+userName.get()+ userPic.get());
}
返回值是nullnull
此处因为线程还未返回,主测试线程已经测试结束,所以直接忽视了线程打印结果,现在这里主线程等待5s后再观察控制台
i got userName in 1001ms,userPic is 照片
i got userName in 1501ms,userName is 张大大
返回值是张大大照片
结果与预期相同,但是整体执行时间为主线程等待的5s后,理论上可以不需要等待5s,但是此处难以把控具体时间
@Test
void threadCallableTest(){
long timeInMillis = System.currentTimeMillis();
Callable userNameCall = new Callable() {
@Override
public Object call() throws Exception {
String userName = threadTestService.getUserName();
System.out.println("i got userName in " + String.valueOf(System.currentTimeMillis()-timeInMillis) + "ms,userName is "+userName);
return userName;
}
};
Callable userPicCall = new Callable() {
@Override
public String call() throws Exception {
String userPic = threadTestService.getUserPic();
System.out.println("i got userName in " + String.valueOf(System.currentTimeMillis()-timeInMillis) + "ms,userPic is "+userPic);
return userPic;
}
};
FutureTask userNameTask = new FutureTask(userNameCall);
new Thread(userNameTask).start();
FutureTask userPicTask = new FutureTask(userPicCall);
new Thread(userPicTask).start();
try {
System.out.println("返回值是"+userNameTask.get()+ userPicTask.get());
} catch ( InterruptedException e ) {
e.printStackTrace();
} catch ( ExecutionException e ) {
e.printStackTrace();
}
}
用时1.729ms,也就是说基本在数据计算完成后,即返回结果,且不会因主线程执行导致返回信息错误
源代码中,callable是个只有call()方法的接口,就不看了
主要看furureTask类,其中的get()方法:
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
其中get方法会判断当前执行状态,如果没完成,会进入java.util.concurrent.FutureTask#awaitDone方法停滞,并等待返回状态
具体停滞方式为:
/**
* Awaits completion or aborts on interrupt or timeout.
*
* @param timed true if use timed waits
* @param nanos time to wait, if timed
* @return state upon completion
*/
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
else if (q == null)
q = new WaitNode();
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
LockSupport.park(this);
}
}
在for(;;)中持续循环,等待状态完成后返回完成状态或异常状态
之后在上面代码看到的report中根据完成状态返回全局变量记录的返回结果