Spring Framework

  • Introduction
  • Inversion of Control:
    • Usages
      • Spring Bean Factory
      • ApplicationContext and Property initialization
      • Injection
        • Constructor Injection
        • Object Injection, Inner Beans, Aliases and idref
      • Initializing Collections
      • Autowiring
      • Bean Scope
      • ApplicationAware&BeanNameAware
      • Bean Definition Inheritance
      • Lifecycle Callbacks
      • BeanPostProcessor
      • BeanFactoryPostProcessor
      • Coding to Interface
      • Annotations
        • The Required Annotation
        • The Autowired Annotation
      • JSR-250 Annotations
      • Component and Stereotype Annotations
      • Using MessageSource To Get Text From Property Files
      • Event Handling in Spring
  • Spring MVC
    • MVC Models
  • 从动态代理到SpringAOP
    • 什么是动态代理
    • 动态代理的实现方式
      • jdkproxy
      • CGLIB
    • SpringAOP中动态代理的体现

Introduction

spingframework

Inversion of Control:

控制指谁来控制对象的创建,传统的应用程序对象的创建是由程序本身控制的,使用 Spring 后是由 Spring 来创建的。正转指程序来创建对象,反转指程序本身不去创建对象,而变为被动接受的对象。

  • ioc是一种编程思想。由主动编程变为被动接收
  • ioc的实现是通过ioc容器来实现的。
  • ioc容器——BeanFactory。

🔗:IoC容器(Ioc : Inversion of control)和Dependency Injection模式

Usages

Spring Bean Factory

使用spring framework提供的基本的工厂特性创建对象,该对象的生命周期由spring管理。对象工厂所做的是从配置文件(bluedprint:spring.xml)中读取该对象工厂必须创建的所有对象。

public class Triangle { 
    public void draw() {
        System.out.println("Triangle drawn");
    }
}

public class DrawingApp {
    public static void main(String[] args) {
        //Triangle triangle = new Triangle();
        //deprecated
        BeanFactory factory = new XmlBeanFactory(new FileSystemResource("spring.xml"));
        Triangle triangle = (Triangle) factory.getBean("triangle");
        triangle.draw();
    }
}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <bean id="triangle" class="com.iamwyj.beanfactory.Triangle" />
</beans>

ApplicationContext and Property initialization

ApplicationContext包含👆的Beanfactory所有的特性之外还有其他特性,例如AOP

public class Triangle {
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public void draw() {
        System.out.println(this.getType() + " triangle drawn");
    }
}

public class DrawingApp {
    public static void main(String[] args) {
        // spring.xml置于src下
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Triangle triangle = (Triangle) context.getBean("triangle");
        triangle.draw();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <bean id="triangle" class="com.iamwyj.applicationcontext.Triangle">
        <!-- Property initialization -->
        <!-- Setter Injection -->
        <property name="type" value="Equilateral"/>
    </bean>
</beans>

Injection

Constructor Injection
public class Triangle {
    private String type;
    private int height;

    public Triangle(String type) {
        this.type = type;
    }
    
    public Triangle(int height) {
        this.height = height;
    }

    public Triangle(String type, int height) {
        this.type = type;
        this.height = height;
    }

    public String getType() {
        return type;
    }

    public int getHeight() {
        return height;
    }

    public void draw() {
        System.out.println(this.getType() + " triangle drawn of height " + this.getHeight());
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <bean id="triangle" class="com.iamwyj.constructorinjection.Triangle">
        <!--  <constructor-arg value="Equilateral" /> -->
        <!--  <constructor-arg type="int" value="20"/> -->
        <!--  <constructor-arg type="java.lang.String" value="20"/> -->
        <constructor-arg index="0" value="Equilateral"/>
        <constructor-arg index="1" value="20"/>
    </bean>
</beans>
Object Injection, Inner Beans, Aliases and idref
public class Point {

    private int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

}

public class Triangle {
    private Point pointA;
    private Point pointB;
    private Point pointC;
    
    public Point getPointA() {
        return pointA;
    }

    public void setPointA(Point pointA) {
        this.pointA = pointA;
    }

    public Point getPointB() {
        return pointB;
    }

    public void setPointB(Point pointB) {
        this.pointB = pointB;
    }

    public Point getPointC() {
        return pointC;
    }

    public void setPointC(Point pointC) {
        this.pointC = pointC;
    }

    public void draw() {
        System.out.println("Point A = ("+this.getPointA().getX()+","+this.getPointA().getY()+")");
        System.out.println("Point B = ("+this.getPointB().getX()+","+this.getPointB().getY()+")");
        System.out.println("Point C = ("+this.getPointC().getX()+","+this.getPointC().getY()+")");
    }

}

public class DrawingApp {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Triangle triangle = (Triangle) context.getBean("triangle-alias");
        triangle.draw();
    }

}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <bean id="triangle" class="com.iamwyj.injectobjects.Triangle"
        name="triangle-name">
        <property name="pointA" ref="point0" />
        <property name="pointB">
            <!-- inner bean -->
            <bean class="com.iamwyj.injectobjects.Point">
                <property name="x" value="-20" />
                <property name="y" value="0" />
            </bean>
        </property>
        <property name="pointC" ref="point2" />
    </bean>

    <!-- Aliases -->
    <alias name="triangle" alias="triangle-alias" />

    <bean id="point0" class="com.iamwyj.injectobjects.Point">
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>

    <bean id="point2" class="com.iamwyj.injectobjects.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
    <!-- <idref/>make sure that there is a bean with id... -->
</beans>

Initializing Collections

import java.util.List;

public class Triangle {
    private List<Point> points;
    
    public List<Point> getPoints() {
        return points;
    }

    public void setPoints(List<Point> points) {
        this.points = points;
    }

    public void draw() {
        for(Point point:points)
            System.out.println("Point = ("+point.getX()+","+point.getY()+")");
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <bean id="triangle" class="com.iamwyj.collections.Triangle">
        <property name="points">
            <list>
                <ref bean = "point0" />
                <ref bean = "point1" />
                <ref bean = "point2" />
            </list>
        </property>
    </bean>
    <bean id="point0" class="com.iamwyj.collections.Point">
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="point1" class="com.iamwyj.collections.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    <bean id="point2" class="com.iamwyj.collections.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
</beans>

Autowiring

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <!-- scope默认为singleton -->
    <!-- byname, byType, constructor  -->
    <bean id="triangle" class="com.iamwyj.autowiringandscope.Triangle" autowire="byName" scope="prototype"/>
    
    <bean id="pointA" class="com.iamwyj.autowiringandscope.Point">
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="pointB" class="com.iamwyj.autowiringandscope.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    <bean id="pointC" class="com.iamwyj.autowiringandscope.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
</beans>

Bean Scope

  • Singleton(和设计模式中所说的singleton不完全相同) - Only once per Spring container
  • Prototype - New bean created with every request and reference。
  • Web-aware Context Bean Scope
    • Request - New bean per servlet request
    • Session - New bean per session
    • Globle Session - New bean per global HTTP session(portlet context) 默认为Singleton,所以spring容器中的bean默认在容器初始化的时候(spring load time)就创建了,而非在调用getBean方法时调用,调用此方法时,spring容器直接将创建好的bean返回给它。但是如果将scope设置为prototype的话,则每次等到调用getBean方法时才调用,并且每次都创建新的实例。

ApplicationAware&BeanNameAware

通过实现ApplicationAware接口方法可以获得ApplicationContext对象; 通过实现BeanNameAware接口方法可以获得该Bean在Spring.xml配置文件中配置的name;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Triangle implements ApplicationContextAware, BeanNameAware {
    private Point pointA;
    private Point pointB;
    private Point pointC;
    private ApplicationContext context = null;
    
    public Point getPointA() {
        return pointA;
    }

    public void setPointA(Point pointA) {
        this.pointA = pointA;
    }

    public Point getPointB() {
        return pointB;
    }

    public void setPointB(Point pointB) {
        this.pointB = pointB;
    }

    public Point getPointC() {
        return pointC;
    }

    public void setPointC(Point pointC) {
        this.pointC = pointC;
    }

    public void draw() {
        System.out.println("Point A = ("+this.getPointA().getX()+","+this.getPointA().getY()+")");
        System.out.println("Point B = ("+this.getPointB().getX()+","+this.getPointB().getY()+")");
        System.out.println("Point C = ("+this.getPointC().getX()+","+this.getPointC().getY()+")");
    }

    @Override
    public void setBeanName(String beanName) {
        System.out.println("Bean name is "+beanName);
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }
}

Bean Definition Inheritance

import java.util.List;
import com.iamwyj.beaninheritance.Point;

public class Triangle {
    private List<Point> points;

    public List<Point> getPoints() {
        return points;
    }

    public void setPoints(List<Point> points) {
        this.points = points;
    }

    public void draw() {
        for (Point point : points)
            System.out.println("Point = (" + point.getX() + "," + point.getY() + ")");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <!-- abstract告诉spring不要创建bean,这是一个模版(template)    -->
    <bean id="parenttriangle" class="com.iamwyj.beaninheritance.Triangle"
        abstract="true">
        <property name="points">
            <list>
                <ref bean="pointA" />
            </list>
        </property>
    </bean>

    <bean id="triangle1" class="com.iamwyj.beaninheritance.Triangle"
        parent="parenttriangle">
        <property name="points">
            <!-- merge的意思是合并继承的集合中的值,否则会覆盖 -->
            <list merge="true">
                <ref bean="pointB" />
            </list>
        </property>
    </bean>

    <bean id="pointA" class="com.iamwyj.beaninheritance.Point">
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="pointB" class="com.iamwyj.beaninheritance.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    <bean id="pointC" class="com.iamwyj.beaninheritance.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
</beans>

Lifecycle Callbacks

package com.iamwyj.lifecyclecallback;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Triangle implements InitializingBean, DisposableBean{
    private Point pointA;
    private Point pointB;
    private Point pointC;
    
    public Point getPointA() {
        return pointA;
    }

    public void setPointA(Point pointA) {
        this.pointA = pointA;
    }

    public Point getPointB() {
        return pointB;
    }

    public void setPointB(Point pointB) {
        this.pointB = pointB;
    }

    public Point getPointC() {
        return pointC;
    }

    public void setPointC(Point pointC) {
        this.pointC = pointC;
    }

    public void draw() {
        System.out.println("Point A = ("+this.getPointA().getX()+","+this.getPointA().getY()+")");
        System.out.println("Point B = ("+this.getPointB().getX()+","+this.getPointB().getY()+")");
        System.out.println("Point C = ("+this.getPointC().getX()+","+this.getPointC().getY()+")");
    }

    // 方式二通过在spring.xml文件中配置 
    public void myInit() {
        System.out.println("My init method called for triangle");
    }
    
    public void myDestroy() {
        System.out.println("My destroy method called for triangle");
    }
    
    // 方式一通过实现接口
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean init method called for triangle");     
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy method called for triangle");       
    }
}


import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DrawingApp {

    public static void main(String[] args) {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        context.registerShutdownHook();
        Triangle triangle = (Triangle) context.getBean("triangle");
        triangle.draw();
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!-- 全局配置 -->
<beans default-init-method="myInit" default-destroy-method="myDestroy">
    <!-- 针对单个的bean -->
    <!-- init-method="myInit" destroy-method="myDestroy" -->
    <bean id="triangle" class="com.iamwyj.lifecyclecallback.Triangle">
        <property name="pointA" ref="point0" />
        <property name="pointB" ref="point1" />
        <property name="pointC" ref="point2" />
    </bean>

    <bean id="point0" class="com.iamwyj.lifecyclecallback.Point">
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="point1" class="com.iamwyj.lifecyclecallback.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    <bean id="point2" class="com.iamwyj.lifecyclecallback.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
</beans>

BeanPostProcessor

package com.iamwyj.beanpostprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class DisplayNameBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("In after initialization method,  bean is "+ beanName);
        return bean;
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException{
        System.out.println("In before initialization method,  bean is "+ beanName);
        return bean;

    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-init-method="myInit" default-destroy-method="myDestroy">
    <bean id="triangle" class="com.iamwyj.beanpostprocessor.Triangle"> <!-- init-method="myInit" destroy-method="myDestroy" -->
        <property name="pointA" ref="point0" />
        <property name="pointB" ref="point1" />
        <property name="pointC" ref="point2" />
    </bean>

    <bean id="point0" class="com.iamwyj.beanpostprocessor.Point">
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="point1" class="com.iamwyj.beanpostprocessor.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    <bean id="point2" class="com.iamwyj.beanpostprocessor.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
    <bean class="com.iamwyj.beanpostprocessor.DisplayNameBeanPostProcessor" />
</beans>

运行结果: BeanPostProcessor

BeanFactoryPostProcessor

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryPP implements BeanFactoryPostProcessor{
    // beanfactory初始之前时候执行
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("My bean factory post processor method is called.");
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-init-method="myInit" default-destroy-method="myDestroy">
    <bean id="triangle" class="com.iamwyj.beanfactorypostprocessor.Triangle"> <!-- init-method="myInit" destroy-method="myDestroy" -->
        <property name="pointA" ref="point0" />
        <property name="pointB" ref="point1" />
        <property name="pointC" ref="point2" />
    </bean>

    <bean id="point0" class="com.iamwyj.beanfactorypostprocessor.Point">
        <!-- property placeholder -->
        <property name="x" value="${pointA.pointX}" />
        <property name="y" value="${pointA.pointY}" />
    </bean>
    <bean id="point1" class="com.iamwyj.beanfactorypostprocessor.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    <bean id="point2" class="com.iamwyj.beanfactorypostprocessor.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
    <bean class="com.iamwyj.beanfactorypostprocessor.MyBeanFactoryPP" />

    <!-- spring提供的bean factory post processor -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
        <property name="locations" value="pointsconfig.properties" />
    </bean>

</beans>

poinsconfig.properties

pointA.pointX=0
pointA.pointY=0

运行结果: BeanPostFactoryProcessor

Coding to Interface

public class Point {

    private int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

}

public interface Shape {
    public void draw();
}

public class Triangle implements Shape {
    private Point pointA;
    private Point pointB;
    private Point pointC;
    
    public Point getPointA() {
        return pointA;
    }

    public void setPointA(Point pointA) {
        this.pointA = pointA;
    }

    public Point getPointB() {
        return pointB;
    }

    public void setPointB(Point pointB) {
        this.pointB = pointB;
    }

    public Point getPointC() {
        return pointC;
    }

    public void setPointC(Point pointC) {
        this.pointC = pointC;
    }

    public void draw() {
        System.out.println("Drawing Triangle");
        System.out.println("Point A = ("+this.getPointA().getX()+","+this.getPointA().getY()+")");
        System.out.println("Point B = ("+this.getPointB().getX()+","+this.getPointB().getY()+")");
        System.out.println("Point C = ("+this.getPointC().getX()+","+this.getPointC().getY()+")");
    }

}

public class Circle implements Shape{
    private Point center;
    public Point getCenter() {
        return center;
    }
    public void setCenter(Point center) {
        this.center = center;
    }
    @Override
    public void draw() {
        System.out.println("Drawing Circle");
        System.out.println("Circle: Point is ("+center.getX()+","+center.getY()+")");
    }

}

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DrawingApp {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Shape shape = (Shape) context.getBean("circle");
        shape.draw();
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <bean id="triangle" class="com.iamwyj.codingtointerface.Triangle">
        <property name="pointA" ref="point0" />
        <property name="pointB" ref="point1" />
        <property name="pointC" ref="point2" />
    </bean>
    <bean id="circle" class="com.iamwyj.codingtointerface.Circle">
        <property name="center" ref="point0" />
    </bean>

    <bean id="point0" class="com.iamwyj.codingtointerface.Point">
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="point1" class="com.iamwyj.codingtointerface.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    <bean id="point2" class="com.iamwyj.codingtointerface.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
</beans>

Annotations

The Required Annotation
package com.iamwyj.annotation;

import org.springframework.beans.factory.annotation.Required;

public class Circle implements Shape{
    private Point center;
    public Point getCenter() {
        return center;
    }
    @Required
    public void setCenter(Point center) {
        this.center = center;
    }
    @Override
    public void draw() {
        System.out.println("Drawing Circle");
        System.out.println("Circle: Point is ("+center.getX()+","+center.getY()+")");
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xmlns:context="http://www.springframework.org/schema/context"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
           http://www.springframework.org/schema/context  
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
          
    <bean id="circle" class="com.iamwyj.annotation.Circle" />

    <!-- @Required注解的bean processor -->
   <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/> 
</beans>
The Autowired Annotation
package com.iamwyj.annotation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class Circle implements Shape{
    private Point center;
    public Point getCenter() {
        return center;
    }
    @Autowired
    @Qualifier("circleRelated")
    public void setCenter(Point center) {
        this.center = center;
    }
    @Override
    public void draw() {
        System.out.println("Drawing Circle");
        System.out.println("Circle: Point is ("+center.getX()+","+center.getY()+")");
    }

}

<?xml version="1.0" encoding="UTF-8"?>
<!-- xml namespace -->
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xmlns:context="http://www.springframework.org/schema/context"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
           http://www.springframework.org/schema/context  
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
      
    <bean id="circle" class="com.iamwyj.annotation.Circle" />

    <bean id="point0" class="com.iamwyj.annotation.Point">
        <qualifier value="circleRelated" />
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="center" class="com.iamwyj.annotation.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    
    <!-- @@Autowired注解 -->
    <bean
        class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />-->
    <!-- 以上所有的关于注解的BeanPostProcessor的注册可以被以下快捷方式替代 -->
    <context:annotation-config/>    

</beans>

JSR-250 Annotations

package com.iamwyj.jsrannotation;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

public class Circle implements Shape {
    private Point center;

    public Point getCenter() {
        return center;
    }

    @Resource(name = "point2")
    // 如果不设置name值,会默认寻找名为center的bean进行注入
    public void setCenter(Point center) {
        this.center = center;
    }

    @PostConstruct
    public void initializeCircle() {
        System.out.println("Init of Circle");
    }

    @PreDestroy
    public void destroyCircle() {
        System.out.println("Destroy of Circle");
    }

    @Override
    public void draw() {
        System.out.println("Drawing Circle");
        System.out.println("Circle: Point is (" + center.getX() + "," + center.getY() + ")");
    }

}

package com.iamwyj.jsrannotation;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DrawingApp {

    public static void main(String[] args) {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        context.registerShutdownHook();
        Shape shape = (Shape) context.getBean("circle");
        shape.draw();
    }

}
/* Output:
* Init of Circle
* Drawing Circle
* Circle Point is: (20, 0)
* Destroy of Circle
*/
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
           http://www.springframework.org/schema/context  
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    <bean id="circle" class="com.iamwyj.jsrannotation.Circle" />

     <bean id="point0" class="com.iamwyj.jsrannotation.Point">
        <qualifier value="circleRelated" />
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="point1" class="com.iamwyj.jsrannotation.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    <bean id="point2" class="com.iamwyj.jsrannotation.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
    
</beans>

Component and Stereotype Annotations

package com.iamwyj.stereotypeannotation;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
//@Component //generic object
//if marked as follows, spring will know what the class was doing.
//@Service
//@Repository //data object
@Controller
public class Circle implements Shape {
    private Point center;

    public Point getCenter() {
        return center;
    }

    @Resource
    public void setCenter(Point center) {
        this.center = center;
    }

    @PostConstruct
    public void initializeCircle() {
        System.out.println("Init of Circle");
    }

    @PreDestroy
    public void destroyCircle() {
        System.out.println("Destroy of Circle");
    }

    @Override
    public void draw() {
        System.out.println("Drawing Circle");
        System.out.println("Circle: Point is (" + center.getX() + "," + center.getY() + ")");
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
           http://www.springframework.org/schema/context  
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    <context:annotation-config />
    <bean id="triangle" class="com.iamwyj.stereotypeannotation.Triangle">
        <property name="pointA" ref="point0" />
        <property name="pointB" ref="point1" />
        <property name="pointC" ref="point2" />
    </bean>


    <bean id="point0" class="com.iamwyj.stereotypeannotation.Point">
        <qualifier value="circleRelated" />
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="point1" class="com.iamwyj.stereotypeannotation.Point">
        <property name="x" value="-20" />
        <property name="y" value="0" />
    </bean>
    <bean id="point2" class="com.iamwyj.stereotypeannotation.Point">
        <property name="x" value="0" />
        <property name="y" value="20" />
    </bean>
    <bean id="center" class="com.iamwyj.stereotypeannotation.Point">
        <property name="x" value="6" />
        <property name="y" value="20" />
    </bean>
    
    <context:component-scan base-package="com.iamwyj.stereotypeannotation"/>
    
</beans>

Using MessageSource To Get Text From Property Files

新建mymessage.properties文件

greeting=Hello!
drawing.circle=Drawing Circle!
drawing.point=Circle: Point is ({0},{1})
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
           http://www.springframework.org/schema/context  
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    <context:annotation-config />
    <bean id="point0" class="com.iamwyj.messagesource.Point">
        <qualifier value="circleRelated" />
        <property name="x" value="0" />
        <property name="y" value="0" />
    </bean>
    <bean id="center" class="com.iamwyj.messagesource.Point">
        <property name="x" value="6" />
        <property name="y" value="20" />
    </bean>
    
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>mymessages</value>
            </list>
        </property>
    </bean>
    <context:component-scan base-package="com.iamwyj.messagesource"/>
</beans>
package com.iamwyj.messagesource;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
//@Component //generic object
//if marked as follows, spring will know what the class was doing.
//@Service
//@Repository //data object
@Controller
public class Circle implements Shape {
    private Point center;
    @Autowired
    private MessageSource messageSource;
    public MessageSource getMessageSource() {
        return messageSource;
    }

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    public Point getCenter() {
        return center;
    }

    @Resource
    public void setCenter(Point center) {
        this.center = center;
    }

    @PostConstruct
    public void initializeCircle() {
        System.out.println("Init of Circle");
    }

    @PreDestroy
    public void destroyCircle() {
        System.out.println("Destroy of Circle");
    }

    @Override
    public void draw() {
        System.out.println(this.messageSource.getMessage("drawing.circle", null, "Default Drawing Message", null));
        System.out.println(this.messageSource.getMessage("drawing.point", new Object[] {this.center.getX(),this.center.getY()}, "Default Points Message", null));
        System.out.println(this.messageSource.getMessage("greeting", null, "Default Greeting", null));
    }

}

Event Handling in Spring

package com.iamwyj.eventhandling;

import org.springframework.context.ApplicationEvent;

public class DrawEvent extends ApplicationEvent {

    public DrawEvent(Object source) {
        super(source);
        // TODO Auto-generated constructor stub
    }

    public String toString() {
        return "Draw Event Occured";
    }
}

package com.iamwyj.eventhandling;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyEventListener implements ApplicationListener {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println(event.toString());
    }
}

package com.iamwyj.eventhandling;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

//@Component //generic object
//if marked as follows, spring will know what the class was doing.
//@Service
//@Repository //data object
@Controller
public class Circle implements Shape, ApplicationEventPublisherAware {
    private Point center;
    @Autowired
    private MessageSource messageSource;
    private ApplicationEventPublisher publisher;

    public MessageSource getMessageSource() {
        return messageSource;
    }

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    public Point getCenter() {
        return center;
    }

    @Resource
    public void setCenter(Point center) {
        this.center = center;
    }

    @PostConstruct
    public void initializeCircle() {
        System.out.println("Init of Circle");
    }

    @PreDestroy
    public void destroyCircle() {
        System.out.println("Destroy of Circle");
    }

    @Override
    public void draw() {
        System.out.println(this.messageSource.getMessage("drawing.circle", null, "Default Drawing Message", null));
        System.out.println(this.messageSource.getMessage("drawing.point",
                new Object[] { this.center.getX(), this.center.getY() }, "Default Points Message", null));
        System.out.println(this.messageSource.getMessage("greeting", null, "Default Greeting", null));
        DrawEvent drawEvent = new DrawEvent(this);
        publisher.publishEvent(drawEvent);
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }
}

Spring MVC

MVC设计思想:任何重定向都能解耦合

springmvc

MVC Models

  • Model1:耦合太高
    MVC Model1

  • Model2:
    MVC Model2

  • C/S:模型层主动推送数据到视图

  • B/S:模型层不能推送数据到视图层

mvc框架要求:

  1. 将url映射到java类或java类的方法
  2. 封装用户提交的数据
  3. 处理请求——调用相关的业务处理封装响应的数据
  4. 将响应数据的数据进行渲染,jsp,html,freemaker等

从动态代理到SpringAOP

什么是动态代理

代理模式可以看作对调用目标的包装,这样对目标代码的调用不是直接发生的,而是通过代理完成,很多动态代理场景也可以看作是装饰器模式的应用。代理的目的可以让调用者与实现这解耦。动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,PRC的调用以及AOP都是基于动态代理,这也用到了设计模式中的代理模式,可以解决很多繁琐的重复编程,这一点在SpringAOP中可以体现,此处的动态表示代理类在运行时产生,而AspectJ对目标代码的生成则是在编译期编织。

动态代理的实现方式

实现动态代理的方式主要有Java自身提供的动态代理(基于反射)以及cglib(基于ASM,直接操作字节码),ASM框架是对字节码类库的封装。

jdkproxy

Java自身提供的动态代理由于是jdk本省支持的,依赖关系小,简化开发,易于维护,但需要调用者实现接口,此种方式具有侵入性。

代码使用示例:

public interface Hello {
    void sayHello();
}

public class HelloImpl implements Hello {
    @Override
    public void sayHello() {
        System.out.println("Hello World");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    //代理可看作是对调用目标的包装
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Invoking sayHello!");
        Object result = method.invoke(target, args);
        return result;
    }
}
import java.lang.reflect.Proxy;

public class MyDynamicProxy {
    public static void main(String[] args) {
        HelloImpl hello = new HelloImpl();
        MyInvocationHandler handler = new MyInvocationHandler(hello);
        //构造代码实例
        Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);
        //使用代理方法
        proxyHello.sayHello();
    }
}

//TODO 构造函数底层源码:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

CGLIB

cglib不需要限定调用者实现接口,也不必为其他相关类增加工作量,因此性能更高。

使用代码示例:

public class Person {
    public String sayHello(String name) {
        System.out.println("-- 正在执行sayHello方法 --");
        //返回简单的字符串
        return name + " Hello, cglib proxy";
    }

    public void eat(String food) {
        System.out.println("我正在吃:" + food);
    }
}
import org.springframework.cglib.proxy.Enhancer;

//此类会通过CGLIB来为Person生成代理类
public class PersonProxyFactory {
    public static Person getAuthInstance() {
        Enhancer en = new Enhancer();
        //设置要代理的目标类
        en.setSuperclass(Person.class);
        //设置要代理的拦截器
        en.setCallback(new AroundAdvice());
        //生成代理类的实例
        return (Person) en.create();
    }
}
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

//先为 CGLIB 提供一个拦截器实现类
public class AroundAdvice implements MethodInterceptor {

    @Override
    public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("执行开始方法前,模拟开始事物...");
        //执行目标方法,并保存目标方法执行后的返回值
        Object rvt = methodProxy.invokeSuper(target, new String[]{"被改变的参数"});
        System.out.println("执行目标方法之后,模拟结束事物...");
        return rvt+ " 新增的内容";
    }
}
public class Main {
    public static void main(String[] args) {
        Person person= PersonProxyFactory.getAuthInstance();
        System.out.println(person.sayHello("孙悟空"));
        person.eat("西瓜");
        System.out.println(person.getClass());
    }
}

SpringAOP中动态代理的体现

  • 事物控制
  • 动态代理
  • 运行时动态生成一个java类