Iman H
Iman H

Reputation: 476

Spring Boot does not inject @Autowired repository into netty classes

I have a Spring Boot application with the following structure:

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?

Upvotes: 1

Views: 674

Answers (2)

crizzis
crizzis

Reputation: 10716

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);
...
}

Upvotes: 5

prost&#253; člověk
prost&#253; člověk

Reputation: 939

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

Upvotes: 0

Related Questions