spring java config M3

January 9th, 2009 by roofimon Leave a reply »

ลองมาดูกันว่าคนที่ไม่ชอบ XML จะสามารถเลิกใช้มันได้ไหมและเมื่อไหร่ คำตอบคือตอนนี้ SpringJavaConfig ออก M3
แล้วนั่นหมายความว่าความฝันของคนเหล่านี้ใกล้เป็นจริงมากขึ้นเรื่อยๆ แต่ก่อนอื่นลองมาดูกันก่อนว่า Java Config จะช่วย้ชีวิตเราง่ายขึ้นอย่างไรได้บ้าง
เราลองมาเขียน Bean สักสองตัวในแบบปัจจุบัน

<beans>
        <bean id="orderService" class="com.acme.OrderService"/>
                <constructor-arg ref="orderRepository"/>
        </bean>
        <bean id="orderRepository" class="com.acme.OrderRepository"/>
                <constructor-arg ref="dataSource"/>
        </bean>
</beans>

จาก config ไฟล์นี้เราสามารถเรียกใช้ bean ของเราได้ด้วยการเขียน code ตามนี้

ApplicationContext ctx = new ClassPathXmlApplicationContext("application-config.xml");
OrderService orderService = (OrderService) ctx.getBean("orderService");

ซึ่งในกรณีที่เราต้องการเปลี่ยนไปใช้ Java Config เราสามารถเปลี่ยนจากการอธิบาย bean ไว้ใน XML ไปเป็นการเพิ่ม Annotation ลงไปใน Java Class ของเราได้เลยดังนี้

@Configuration
public class ApplicationConfig {
        public @Bean OrderService orderService() {
                return new OrderService(orderRepository());
        }
        public @Bean OrderRepository orderRepository() {
                return new OrderRepository(dataSource());
        }
        public @Bean DataSource dataSource() {
                // instantiate and return an new DataSource …
        }
}

ดังนั้นวิธีการใช้งานก็จะเปลี่ยนไปเล็กน้อย

JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(ApplicationConfig.class);
OrderService orderService = ctx.getBean(OrderService.class);

AnnotationApplicationContext ถูกเลิกใช้
ข้างบนคือข่าวดี และแน่นอนก็ต้องมีข่าวร้ายเพราะ AnnotationApplicationContext กำลังจะถูกเลิกใช้งานสถานะตอนนี้เป็น Deplicate และจะถูกตัดทิ้งไปเมื่อ release 1.0.0rc1ในเมื่อ
AnnotationApplicationContext ก็สามารถทำ Annotation-Driven Injection ได้อยู่แล้วคำตอบก็คือ JavaConfig ทำในสิ่งที่แตกต่างกว่า Annotaion-Driven Injection
แต่ก็จะมีคำถามจตามมาคือแล้วมันต่างกันยังไง เรามาดูเป็นข้อๆกันเลย

Type-Safe Improvements
ข้อแรกก็กรี๊ดคือไม่ต้องทำ Casting ไม่ต้อง Lookup ผ่านชื่อที่เป็น String อีกต่อไปดังนี้

JavaConfigApplicationContext context = new JavaConfigApplicationContext(AppConfig.class);
OrderService orderService = context.getBean(OrderService.class);

แต่ปัญหาคือในกรณีที่มี Bean มากกว่าหนึ่งตัวใช้คลาส OrderService เหมือนกันเราจะทำยังไงมีทางออกสามทาง ไปอ่านเองก่อนนะครับ ที่นี่

สามารถ JavaConfig ใน Web-Tier ได้
เนื่องจากข้อจำกัดหลักของ Spring คือมันจะโหลด Application Context ผ่าน XML เท่านั้นดังนั้ในกรณีที่เราต้องเอาไปใช้ใน Web เราต้องบอก web.xml ว่า เห้ยไม่มีแล้วเค้าให้โหลดแบบใหม่นะ
โดยเราสามารถทำได้ดังนี้

<web-app>
    <!– Configure ContextLoaderListener to use JavaConfigWebApplicationContext
         instead of the default XmlWebApplicationContext –>
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.config.java.context.JavaConfigWebApplicationContext</param-value>
    </context-param>
    <!– Configuration locations must consist of one or more comma- or space-delimited
         fully-qualified @Configuration classes –>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>example.RootApplicationConfig</param-value>
    </context-param>
    <!– Bootstrap the root application context as usual using ContextLoaderListener –>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!– Declare a Spring MVC DispatcherServlet as usual –>
    <servlet>
        <servlet-name>dispatcher-servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!– Configure DispatcherServlet to use JavaConfigWebApplicationContext
             instead of the default XmlWebApplicationContext –>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.config.java.context.JavaConfigWebApplicationContext</param-value>
        </init-param>
        <!– Again, config locations must consist of one or more comma- or space-delimited
             and fully-qualified @Configuration classes –>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>example.web.WebBeansConfig</param-value>
        </init-param>
    </servlet>
</web-app>

ข้อต่อไปเพิ่มเติมความสามารถเรื่อง @import เข้าไปอีก
อันนี้ต้องดูตัวอย่าง

@Configuration
public class FooConfig {
        public @Bean Foo foo() { … }
        public @Bean Bar bar() { … }
}
@Import(FooConfig.class)
@Configuration
public class ApplicationConfig {
        public @Bean ServiceA serviceA() { … }
}
JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(ApplicationConfig.class);
// foo, bar, and serviceA beans will all be available
ctx.getBean(ServiceA.class); // works
ctx.getBean(Foo.class); // works too

External Resource
แต่ก่อนเราต้องใช้ properties ไฟล์ในการเก็บค่าคงที่ที่ใช้งานนอกระบบต่างๆเช่น username, password, url ในการติดต่อกับ Database แต่สำหรับ JavaConfig เราสามารถปวดกระโหลกมาขึ้นด้วยการยัดมันลงไปในคลาสได้เลยดังนี้

@Configuration
@ResourceBundles("classpath:/com/acme/datasource")
public abstract class ApplicationConfig {
        public @Bean OrderService orderService() {
                return new OrderServiceImpl(orderRepository());
        }
        public @Bean OrderRepository orderRepository() {
                return new JdbcOrderRepository(dataSource());
        }
        public @Bean DataSource dataSource() {
                return new DriverManagerDataSource(url(), username(), password());
        }
        abstract @ExternalValue("datasource.url") String url();
        abstract @ExternalValue("datasource.username") String username();
        abstract @ExternalValue("datasource.password") String password();
}

เป็นไงครับปวดหัวกว่าเดิมหรือดีกว่าเดิม ==’

Advertisement

Leave a Reply

You must be logged in to post a comment.