Bu yazımızda Spring IoC tarafından instantiate edilmiş Bean’ler üzerinde cache’leme işlemi nasıl yapılır bunu inceleyeceğiz.
Neler Gerekli
- JDK 1.8
- Maven 3.2+
- Favori IDE’niz
- Postman
Bağımlılıkları Tanımlayalım
Bağımlılık olarak yalnızca Spring Starter Cache eklememiz yeterli. Bu durumda mevcut pom.xml dosyamız bu şekilde olacak:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
Kodlamaya Başlayalım
Cache için kullanacağımız bir java sınıfı tanımlayacağız. Sınıfımızın ismi Movie , imstance variable’ları ise title ve director olsun. Ayrıca bu dosyamız da model package’ı altında bulunsun.
public class Movie { private String title; private String director; public Movie(String title, String director) { this.title = title; this.director = director; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDirector() { return director; } public void setDirector(String director) { this.director = director; } @Override public String toString() { return "Movie{" + "title='" + title + '\'' + ", director='" + director + '\'' + '}'; } }
Devamında ise veri çekmek için kullanacağımız bir Repository interface’ine ihtiyacımız var. Bunu da repository adında package oluşturarak orada oluşturalım. Daha sonra ise bu interface’imizi implemente edeceğiz. Title ile arama yapabileceğimiz bir metod barındıran interface tanımlamamızı yapalım:
public interface MovieRepository { Movie findByTitle(String title); }
Interface’imiz için implementasyon yapalım ve buda repository package’ının içerisinde impl isminde ayrı bir package içerisinde bulunusun. Spring tarafından görülmesi içinde @Component olarak belirtelim. Ayrıca içerisine bir de 2 saniye boyunca beklemesi için sleep komutunu verelim. Uygulamayı çalıştırdığımızda findByTitle metodu her çağırıldığında 2 saniye beklemesi gerekecek. Ancak bunu cache ettiğimiz için bu durum bizi etkilemeyecek. Devam edelim.
@Component public class MovieRepositoryImpl implements MovieRepository { @Override @Cacheable("movies") public Movie findByTitle(String title) throws InterruptedException { Thread.sleep(2000); return new Movie(title, "director X"); } }
Uygulamamız çalıştığında biizm için işleri yapacak olan bir Runner class’ı tanımlayalım ve bu CommandLineRunner’ı implement etsin. Ayrıca MovieRepository interface’imizi de Dependency Injection ile burada kullanalım. Fark ettiyseniz implementasyonu sağladığımız MovieRepositoryImpl sınıfını kullanmıyoruz. Çünkü Spring bu interface’i implement eden tek sınıfın bu olduğunu bildiği için bunu bizim için algılıyor ve o sınıftan bir Bean oluşturuyor. Eğer ki birden fazla implementasyon sağlayan sınıf olsaydı hata verecekti. Bu seferde hangi sınıfı kullanmak istersen ona gidip @Primary ile o sınıfı kullanmak istediğimizi belirtecektik. Ya da diğer bir yöntem olarak @Qualifier ile hangi sınıfı kullanmak istediğimizi verecektik. Bu daa başka bir yazının konusu olsun artık.
@Component public class Runner implements CommandLineRunner { private static final Logger log = LoggerFactory.getLogger(Runner.class); private final MovieRepository movieRepository; public Runner(MovieRepository movieRepository) { this.movieRepository = movieRepository; } @Override public void run(String... args) throws Exception { log.info("movie'ler için kalkış"); log.info(movieRepository.findByTitle("film 1").toString()); log.info(movieRepository.findByTitle("film 2").toString()); log.info(movieRepository.findByTitle("film 3").toString()); log.info(movieRepository.findByTitle("film 4").toString()); } }
Main metodumuzun bulunduğu sınıfımızı da @EnableCaching ile notasyonunu belirtelim.
@SpringBootApplication @EnableCaching public class CachingApplication { public static void main(String[] args) { SpringApplication.run(CachingApplication.class, args); } }
Test Edelim
Log çıktılarında ki sürelere dikkat edelim.
2020-11-26 21:05:30.227 INFO 8164 --- [ main] c.c.caching.CachingApplication : Starting CachingApplication using Java 1.8.0_265 2020-11-26 21:05:30.230 INFO 8164 --- [ main] c.c.caching.CachingApplication : No active profile set, falling back to default profiles: default 2020-11-26 21:05:30.973 INFO 8164 --- [ main] c.c.caching.CachingApplication : Started CachingApplication in 1.262 seconds (JVM running for 2.231) 2020-11-26 21:05:30.976 INFO 8164 --- [ main] com.codingbytime.caching.Runner : movie'ler için kalkış 2020-11-26 21:05:30.979 INFO 8164 --- [ main] com.codingbytime.caching.Runner : Movie{title='film 1', director='director X'} 2020-11-26 21:05:30.981 INFO 8164 --- [ main] com.codingbytime.caching.Runner : Movie{title='film 2', director='director X'} 2020-11-26 21:05:30.984 INFO 8164 --- [ main] com.codingbytime.caching.Runner : Movie{title='film 3', director='director X'} 2020-11-26 21:05:30.985 INFO 8164 --- [ main] com.codingbytime.caching.Runner : Movie{title='film 4', director='director X'}