Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run DelegatingSecurityContextRunnable every time when tomcat creates new Thread

I have an spring app which is using tomcat with websockets. I would like to use the DelegatingSecurityContextRunnable to be executed every time when tomcat creates a new thread, i.e. warp the tomcat thread. Does anyone know how this is done. The reason for the question can be found.here

Maybe this can be done with using AOP and some advice?

like image 566
Tito Avatar asked Nov 08 '22 20:11

Tito


1 Answers

In Spring boot you can configure a Wrapper by hooking into the Tomcat connector. See this as an example:

@Bean
    public EmbeddedServletContainerFactory servletContainerFactory() {
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();

        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {

            @Override
            public void customize(Connector connector) {
                AbstractProtocol protocolHandler = (AbstractProtocol) connector.getProtocolHandler();
                TaskQueue taskqueue = new TaskQueue() {
                    @Override
                    public boolean offer(Runnable e, long timeout, TimeUnit unit) throws InterruptedException {
                        return super.offer(new MyRunnable(e), timeout, unit);
                    }

                    @Override
                    public boolean offer(Runnable o) {
                        return super.offer(new MyRunnable(o));
                    }
                };
                TaskThreadFactory tf = new TaskThreadFactory("artur-" + "-exec-", false, 0);
                ThreadPoolExecutor e = new ThreadPoolExecutor(10, 10, 1000, TimeUnit.SECONDS, taskqueue);
                taskqueue.setParent(e);
                protocolHandler.setExecutor(e);
            }
        });
        return factory;
    }

And here is my custom Runable (this can be any wrapper, i did not bother implementing exactly yours):

static class MyRunnable implements Runnable {

        private Runnable r;

        public MyRunnable(Runnable r) {
            this.r = r;
        }

        @Override
        public void run() {
            System.out.println("Custom runable");
            runInner();
        }

        void runInner() {
            r.run();
        }

    }

And here are my imports:

import java.util.concurrent.TimeUnit;

import org.apache.catalina.connector.Connector;
import org.apache.coyote.AbstractProtocol;
import org.apache.tomcat.util.threads.TaskQueue;
import org.apache.tomcat.util.threads.TaskThreadFactory;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.PropertySource;

What this does:

The Tomcat connector initialises itself. You can set the executor to use, in which case Tomcat will stop creating its own configuration and instead use yours.

By overwriting the offer methods in the queue, you have the chance to wrap your Runnable in any custom Runnable. In my case, for testing, I simply added a Sysout to see that everything is working correctly.

The Threadpool implementation I used is an exact copy of the tomcat default (minus the properties). This way, behaviour stays the same, except that any Runnable is now your delegating wrapper.

When I test that, my console prints:

 Custom runable

I hope this is what you were looking for.

I use spring boot, but this is essentially a tomcat issue not a spring issue. You can adapt the solution to your specific scenario.

-- Artur

like image 120
pandaadb Avatar answered Nov 15 '22 13:11

pandaadb