0
votes

I have a Spring Boot application with the following structure:

  • com.test (Root Class)
  • com.test.jpa (JPA Entities and Repositories)
  • com.test.netty (netty TCP server)

The root class is:

@ComponentScan(basePackages = {"com.test"})
//@EnableJpaRepositories
//@EntityScan
public class MyApplication {
...

The Netty Server:

package com.test.netty;

@Service
@Slf4j
public class NettyServer {

    private EventLoopGroup boss = new NioEventLoopGroup();
    private EventLoopGroup work = new NioEventLoopGroup();

    @PostConstruct    
    public void start() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(boss, work).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
//                  .option(ChannelOption.SO_BACKLOG, 1024)
                .handler(new LoggingHandler(LogLevel.INFO)).childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true).childHandler(new ServerChannelInit());
        try {
            ChannelFuture future = bootstrap.bind().sync();
            if (future.isSuccess()) {
                log.info("Netty Server Started!");

            }
        } catch (InterruptedException ie) {
            log.error("Error Initializing Netty Server. Error: " + ie.getMessage());
        }

    }

    @PreDestroy
    public void destroy() throws InterruptedException {
        boss.shutdownGracefully().sync();
        work.shutdownGracefully().sync();
        log.info("Netty Server Shut Down!");
    }

and:

public class ServerChannelInit extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline().addLast("mainHandler", new ServiceHandler());
        
    }

and:

package com.test.netty;
@Component
public class ServiceHandler extends ChannelInboundHandlerAdapter {

    private SomeEntity en;

    @Autowired
    SomeRepository sr;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    // Read data and persist some entitys using injected repository

And repository:

package com.test.jpa;

//@Repository
public interface SomeRepository extends JpaRepository<SomeEntity, BigInteger> {

}

The problem is: Repository is not injected into com.test.netty classes. I use it in root class and in JUnit tests without any problem. I added @Repository to the repository and also added repo packages in @EnableJPARepositories but nothing changed.

Any ideas?

2
@Repository is commented out if you remove the comment signs it should work.Jens
It doesn't work even by adding @RepositoryIman H
Can you show us the stacktrace?Bar Hoshen
@BarHoshen The exception is NullPointerException and the stacktrace does not contain any useful information. The exception thrown because "sr" is null.Iman H
You've left out the most important part of your code which is the ... after ServerBootstrap bootstrap = new ServerBootstrap();. How are you registering the handler with the ServerBootstrap? There is no ServiceHandler autowired into NettyServer (unless there's setter injection going on and you also left that part out), so how are you obtaining the reference to the ServiceHandler bean?crizzis

2 Answers

4
votes

Well, if you're creating an instance of ServiceHandler yourself rather than using the bean instance Spring creates for you, of course no dependency injection will be performed. You need to inject the ServiceHandler bean into ServerChannelInit as well as make ServerChannelInit a @Component itself:

@Component
public class ServerChannelInit extends ChannelInitializer<SocketChannel>{

    private final ServiceHandler handler;

    public ServerChannelInit(ServiceHandler handler) {
        this.handler = handler;
    }

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline().addLast("mainHandler", handler);
        
    }
    ...
}

and then inject ServerChannelInit into NettyServer:

@Service
@Slf4j
public class NettyServer {

    private final ServerChannelInit channelInit;

    public NettyServer(ServerChannelInit channelInit) {
        this.channelInit = channelInit;
    }

    private EventLoopGroup boss = new NioEventLoopGroup();
    private EventLoopGroup work = new NioEventLoopGroup();

    @PostConstruct    
    public void start() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(boss, work).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
//                  .option(ChannelOption.SO_BACKLOG, 1024)
                .handler(new LoggingHandler(LogLevel.INFO)).childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true).childHandler(channelInit);
...
}
0
votes

I just executed with the followings, just add @SpringBootApplication in your main class. Uncomment @Repository

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

@Repository
public interface SomeRepository extends JpaRepository<Person, BigInteger> {

     void foo();
}


@Component
public class SampleRepo implements SomeRepository{

    @Override
    public void foo() {
        System.out.println("Called...." );
    }
}
@RestController
public class ServiceHandler  {


    @Autowired
    private SomeRepository sr;

    @GetMapping("/hello")
    public void call(){
        sr.foo();

    }
}

It works!

enter image description here