在我们入职时候被分配的任务大多数是在改bug,如何在不改变当前垃圾代码的情况下去修改方法逻辑呢?
对于类的修改可以使用切面或者子类继承、对于接口的修改可以使用切面或者动态代理
以前那些人些server层次都不写接口的,直接写类。如下结构
contorl结构:
@Autowired
HelloServer helloServer; //当前HelloServer 不是接口而是一个类
@GetMapping("/hello") // 定义了一个请求
String hello(){
return helloServer.hello();
}
servser直接写的类
@Slf4j
@Service
public class HelloServer {
@Autowired
UserMapper userMapper;
public String hello() {
log.info("执行的是HelloServer");
return userMapper.selectList(null).toString();
}
}
这个时候我们该如何保留这个垃圾代码的情况下做出修改呢?
@Slf4j
@Service("HelloServerChild")
public class HelloServerChild extends HelloServer{
@Autowired
UserMapper userMapper;
@Override
public String hello() {
// 重写hello 把逻辑推倒重来
log.info("执行的是HelloServerChild");
Map map=new HashMap();
map.put("name",12);
return userMapper.selectByMap(map).toString();
}
}
再注入时候只要再加入注解即可
contorl中:
@Autowired
@Qualifier("HelloServerChild") //注入子类对象
HelloServer helloServer;
@GetMapping("/hello")
String hello(){
return helloServer.hello(); //调用的是子类中的方法
// 如果调用的是其他中的方法,(即子类中没有的方法)依旧执行的是原来的逻辑
}
和上面结构对比,写的server写的是标准结构server和serverImp,再修改方法逻辑时候可以选择动态代理和切面
contorl:中
@Autowired
TestProServer testProServer; //TestProServer 是一个接口
@GetMapping("/getValue")
String getValue(){
return testProServer.getValue();
}
server是标准结构
public class TestServserImpl implements TestProServer {
@Autowired
UserMapper userMapper;
@Override
public String getValue() {
log.info("执行的是:TestServserImpl");
return userMapper.selectList(null).toString();
}
}
那么如何修改代码逻辑呢?
创建代理对象
@Slf4j
@Component
public class ProxyHelloServer {
@Autowired
UserMapper userMapper;
public TestProServer createProxy(TestProServer helloServer){
// 代理对象 当前类加载器 当前接口 逻辑
return (TestProServer)Proxy.newProxyInstance(ProxyHelloServer.class.getClassLoader(), new Class[]{TestProServer.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Objects.equals("getValue",method.getName())){
// 执行的是getValue ,那么方法将被构建
Map map=new HashMap();
map.put("name",12);
log.info("执行的是代理中的方法");
return userMapper.selectByMap(map).toString();
}else {
// 执行其他方法时候将会执行原来的方法
return method.invoke(helloServer,args);
}
}
});
}
}
修改contorl中的对象--更换成代理对象
@Autowired
TestProServer testProServer; //TestProServer 是一个接口
@GetMapping("/getValue")
String getValue(){
return testProServer.getValue();
}
@Autowired
ProxyHelloServer proxyHelloServer; //代理工厂
@PostConstruct //类的生命周期 再类创建完成时候执行
void SetHelloServer(){
// 把TestProServer对象更换成代理对象
this.testProServer= proxyHelloServer.createProxy(testProServer);
}
注意:子类继承和动态代理本质对代码都是添加而不是修改原码,减少了git冲突
aop切面可以对类和接口进行修改。
前面的contorl层次和server层次都不需要有一点点改变,只是新加入一个aop类,
对于类和接口都能实现代理
@Slf4j
@Component
@Aspect // 标识为切面类
public class ReviseServerAop {
@Autowired
UserMapper userMapper;
// 对hello 方法进行逻辑重写
@Around("execution(public String com.example.demo.demos.server.HelloServer.hello())")
public String ReviseHelloServerTohello(ProceedingJoinPoint joinPoint){
// 环绕通知
Map map=new HashMap();
map.put("name",12);
log.info("执行的是AOP中的方法");
return userMapper.selectByMap(map).toString();
}
// 对getValue 方法进行逻辑重写
@Around("execution(public String com.example.demo.demos.server.TestProServer.getValue())")
public String ReviseTestProServerTogetValue(ProceedingJoinPoint joinPoint){
// 环绕通知
Map map=new HashMap();
map.put("name",12);
log.info("修改TestProServer执行的是AOP中的方法");
return userMapper.selectByMap(map).toString();
}
}
ProceedingJoinPoint 对象中的方法
proceed():执行原始方法。
getArgs():获取方法的参数数组。
getTarget():获取目标对象。
getSignature():获取被代理方法的签名。
toShortString():获取连接点的短字符串表示形式。
getThis():获取代理对象。返回代理对象。