如何高效地修改公司的垃圾代码

一、前言

在我们入职时候被分配的任务大多数是在改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切面

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():获取代理对象。返回代理对象。

你可能感兴趣的:(java,开发语言)