Spring笔记整理

Spring

IOC概念解析


ioc简单代码示例
IMessage.java

    public interface IMessage {
        public abstract String getMessage();
        }

Message.java

public class Message implements IMessage {
    @Override
    public String getMessage() {
    return "Hello World!";
    }
}

NewMessage.java

public class NewMessage implements IMessage {
        @Override
        public String getMessage() {
            return "Hello Every One!";
        }
    }

message.properties

    1=com.alyshen.spring.Message
    2=com.alyshen.spring.NewMessage

MessageFactory.java

    public class MessageFactory {
    
        public static IMessage create(String key) {
    
    //      if ("1".equals(key)) {
    //          //工厂还是依赖这个类
    //          return new Message();
    //      }
    //      
            // 使用资源文件
            ResourceBundle bundle = ResourceBundle.getBundle("message");
            String _class = bundle.getString(key);
            try {
                return (IMessage) Class.forName(_class).newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

MainClass.java

    public class MainClass {
    
        public static void main(String[] args) {
            // 这个类强依赖Message这个类
            // Message msg = new Message();
            
            // 我们不想看到Message这个具体的产品
            // IMessage msg = new Message();
    
            IMessage msg = MessageFactory.create("1");
            System.out.println(msg.getMessage());
    
            msg = MessageFactory.create("2");
            System.out.println(msg.getMessage());
        }
    }

Spring环境配置及IOC工厂应用

用到的包以及文件

包以文件 说明
applicationContext.xml Spring配置文件
spring-context-3.2.0.M1.jar 主要提供bean工厂的实现类,工厂就在里头,但是接口在spring-beans-3.2.0.M1.jar里头
spring-beans-3.2.0.M1.jar bean工厂在里头
spring-core-3.2.0.M1.jar Spring核心包
spring-expression-3.2.0.M1.jar 支持spring表达式的
spring-asm-3.2.0.M1.jar 动态生成一些类的(动态生成字节码的类)
commons-logging-1.1.1.jar 依赖包(公共日志包)

spring配置文件:applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="msg1" class="com.alyshen.spring.Message" />
    <bean id="msg2" class="com.alyshen.spring.NewMessage" />
</beans>

使用spring的bean工厂

public class MainClass {
    public static void main(String[] args) {
    // 使用spring 的bean工厂
    BeanFactory factory = new ClassPathXmlApplicationContext(
    "applicationContext.xml");
    // 使用通配符
    // BeanFactory factory = new ClassPathXmlApplicationContext("app*.xml");

    IMessage msg = (IMessage) factory.getBean("msg1");
    System.out.println(msg.getMessage());

    // 我们自己的bean工厂
    msg = MessageFactory.create("2");
    System.out.println(msg.getMessage());
    }
}

Spring依赖注入的基本方法

set方法注入示例
UserManager.java

public class UserManager {
    // 依赖set方法注入
    private String driverCalss;
    private String url;
    private String username;
    private String password;

    public void addUser() {
        System.out.println(this.toString());
        System.out.println("用户管理_添加用户!");
    }

    public void setDriverCalss(String driverCalss) {
        this.driverCalss = driverCalss;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public String toString() {
        return "UserManager [driverCalss=" + driverCalss + ", url=" + url
        + ", username=" + username + ", password=" + password + "]";
    }
}

UserAction.java

public class UserAction {
    private UserManager manager = null;

    public void setManager(UserManager manager) {
    System.out.println("调用属性manager的set方法注入!");
    this.manager = manager;
    }

    public String execute() {
    this.manager.addUser();
    return "success";
    }
}

spring配置文件:applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="userAction" class="com.alyshen.spring.UserAction">
        <!-- 
        通过属性的set方法将实例的注入 
        -->
        <property name="manager" ref="userManager" />
        </bean>

        <bean id="userManager" class="com.alyshen.spring.UserManager">
        <!-- 
        通过属性的set方法将数据的注入 
        -->
        <property name="driverCalss" value="jdbc.mysql.Driver" />
        <property name="username" value="root" />
        <property name="password" value="654321" />
        <property name="url" value="jdbc:mysql://localhost:3306/mydb" />
    </bean>
</beans>

MainClass.java

    public static void main(String[] args) {
    
        // 使用spring 的bean工厂
        BeanFactory factory = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        // BeanFactory factory = new ClassPathXmlApplicationContext("app*.xml");
    
        UserAction ua = (UserAction) factory.getBean("userAction");
        System.out.println(ua.execute());
    }

Scope属性和BeanFactoryAware接口

UserManager.java

public class UserManager {

    // 依赖set方法注入
    private String driverCalss;
    private String url;
    private String username;
    private String password;

    public void addUser() {
        System.out.println("用户管理_添加用户!");
    }
    //各种set及get方法
    ……
}

UserAction.java

/**
* 实现接口BeanFactoryAware
*/
public class UserAction implements BeanFactoryAware {
    private UserManager manager = null;

    public void setManager(UserManager manager) {
        // System.out.println("调用属性manager的set方法注入!");

        this.manager = manager;
    }

    public String execute() {
        // 每次调用这方法都重新创建bean工厂耗费资源,丧失性能
        // BeanFactory factory = 
        //      new ClassPathXmlApplicationContext("applicationcontext.xml");

        // 非要实现单列对象注入多例对象属性实现:
        // 重新为属性赋值
        manager = (UserManager) factory.getBean("userManager");

        System.out.println(manager);
        this.manager.addUser();
        return "success";
    }

    BeanFactory factory = null;

    @Override
    public void setBeanFactory(BeanFactory factory) throws BeansException {
        // TODO Auto-generated method stub
        this.factory = factory;
    }
}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- 
    scope="singleton":单例(默认),因为是单例,所以属性在创建实例时注入一次,
    如果想多次注入属性实体,见 UserAction.java,首先注入的属性实体必须是多例
    不使用工厂注入
    scope="prototype":多例 
    -->
    <bean id="userAction" class="com.alyshen.spring.UserAction"
        scope="singleton">
        <!-- 
        通过属性的set方法将实例的注入 
        <property name="manager" ref="userManager" />
        -->
    </bean>

    <bean id="userManager" class="com.alyshen.spring.UserManager"
        scope="prototype">
        <!-- 通过属性的set方法将数据的注入 -->
        <property name="driverCalss" value="jdbc.mysql.Driver" />
        <property name="username" value="root" />
        <property name="password" value="654321" />
        <property name="url" value="jdbc:mysql://localhost:3306/mydb" />
    </bean>
</beans>

MainClass.java

public static void main(String[] args) {
    // UserAction userAction = new UserAction();
    // UserManager manager = new UserManager();
    // userAction.setManager(manager);

    // 使用spring 的bean工厂
    // BeanFactory factory = new ClassPathXmlApplicationContext("app*.xml");
    BeanFactory factory = new ClassPathXmlApplicationContext(
            "applicationcontext.xml");
    UserAction ua = (UserAction) factory.getBean("userAction");
    System.out.println(ua);
    System.out.println(ua.execute());
    
    ua = (UserAction) factory.getBean("userAction");
    System.out.println(ua);
    System.out.println(ua.execute());
    
    ua = (UserAction) factory.getBean("userAction");
    System.out.println(ua);
    System.out.println(ua.execute());
}

id_name_ref(bean、local、parent)等属性的用法
applicationContext.xml

<!-- id命名严格,name="/aaa":还好可以加斜杠 -->
<bean id="userAction" class="com.alyshen.spring.UserAction"
    scope="singleton">
    <property name="manager">
        <!-- 
        local="":本地的bean
        bean="":注入的bean
        parent="":父文件的bean
        -->
        <ref bean="manager" />
    </property>
</bean>

MainClass.java

    /**
     * BeanFactory factory = new
     * ClassPathXmlApplicationContext("applicationContext02.xml");
     * 
     * 将factory作为父工厂(已不使用)
     * BeanFactory fay = new XmlBeanFactory( newClassPathResource(
     * "applicationContext.xml"), factory );
     */

set方法注入集合属性

UserAction.java

public class UserAction {

    public List list = null;
    public Set set = null;
    public Map map = null;
    public Properties props = null;

    public void setList(List list) {
        this.list = list;
    }

    public void setSet(Set set) {
        this.set = set;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    public void setProps(Properties props) {
        this.props = props;
    }
}

applicationContext.xml

<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
    <!-- 
    id命名严格,name="/aaa":还好可以加斜杠 
    --> 
    <bean id="userAction" class="com.alyshen.spring.UserAction"
        scope="singleton">

        <property name="list">
            <list>
                <value>zhaoliou</value>
                <ref local="cur" />
            </list>
        </property>

        <property name="set">
            <set>
                <value>dfdsf</value>
                <value>155.54</value>
                <value>1115</value>
                <value type="java.lang.String">true</value>
            </set>
        </property>

        <property name="map">
            <map>
                <entry key="u1">
                    <value>user1</value>
                </entry>
                <entry key="u2">
                    <value>user2</value>
                </entry>
            </map>
        </property>

        <property name="props">
            <props>
                <prop key="driverClass">jdbc.mysql.Driver</prop>
                <prop key="username">root</prop>
                <prop key="password">654321</prop>
                <prop key="url">jdbc:mysql://localhost:3306/mydb</prop>
            </props>
        </property>
    </bean>

    <bean id="cur" class="java.util.Date" />
</beans>
  1. MainClass.java
public static void main(String[] args) {

    BeanFactory factory = new ClassPathXmlApplicationContext(
            "applicationContext.xml");
    UserAction userAction = (UserAction) factory.getBean("userAction");

    System.out.println("---------------list------------");

    for (Object o : userAction.list) {
        System.out.println(o);
    }

    System.out.println("---------------set------------");

    for (Object o : userAction.set) {
        System.out.println(o);
    }

    System.out.println("----------------map-----------");

    for (Iterator iter = userAction.map.entrySet().iterator(); iter
            .hasNext();) {
        System.out.println(iter.next());
    }

    for (Object key : userAction.map.keySet()) {
        System.out.println(key + ":" + userAction.map.get(key));
    }

    System.out.println("--------------props-------------");

    Properties prop = userAction.props;

    System.out.println(prop.get("driverClass"));
    System.out.println(prop.get("username"));
    System.out.println(prop.get("password"));
    System.out.println(prop.get("url"));
}

构造注入及注意事项

  1. A.java
public class A {
    private int id;
    private String username;
    private String password;
    private char sex;
    private Date birthday;

    @Override
    public String toString() {
        return "A [id=" + id + ", username=" + username + ", password="
                + password + ", sex=" + sex + ", birthday=" + birthday + "]";
    }

    public A(int id, String username, String password, char sex, Date birthday) {
        super();
        this.id = id;
        this.username = username;
        this.password = password;
        this.sex = sex;
        this.birthday = birthday;
    }
    //各种set、get方法
    ……
}
  1. applicationContext.xml
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <bean id="a" class="com.alyshen.spring.A">
        <!-- 
        构造方法注入属性,没有设置name属性时,属性要和构造方法的设置属性顺序一致,
        不一致的话可以使用index 
        -->
        <constructor-arg index="4" ref="cur" />
        <constructor-arg value="1" />
        <constructor-arg value="zhaoliou" />
        <constructor-arg value="1111" />
        <constructor-arg value="男" />
    </bean>
    <bean id="cur" class="java.util.Date" />
</beans>
  1. MainClass.java
public static void main(String[] args) {
    BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");

    A a = (A) factory.getBean("a");
    System.out.println(a.toString());
}
  1. 注意事项

a) A.java

public class A {

    private B b;

    public void setB(B b) {
        this.b = b;
    }

    /**
     * 参数构造器
     */
    public A(B b) {
        super();
        this.b = b;
    }

    /**
     * 默认构造器
     */
    public A() {
        super();
    }
}

b) B.java

public class B {

    private A a;

    public void setA(A a) {
        this.a = a;
    }

    public B(A a) {
        super();
        this.a = a;
    }

    public B() {
        super();
    }
}

c) applicationContext.xml

<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <bean id="a" class="com.alyshen.spring.A">
        <!-- 
        不可以互相都使用构造器注入对方
        <constructor-arg ref="b" /> 
        -->
        <property name="b" ref="b" />
    </bean>

    <bean id="b" class="com.alyshen.spring.B">
        <!--
        <constructor-arg ref="a" /> 
        -->
        <property name="a" ref="a" />
    </bean>
</beans>

自动注入及注意事项

  1. UserManager.java
public class UserManager {

public void addUser() {

    System.out.println("添加用户!");
}
}
  1. UserAction.java
public class UserAction {

    private UserManager manager = null;

    /**
     * 参数构造器注入
     */
    public UserAction(UserManager manager) {
        super();
        this.manager = manager;
    }

    /**
     * set方法注入
     */
    public void setManager(UserManager manager) {
        System.out.println("调用manager的set方法注入!");
        this.manager = manager;
    }

    public String execute() {
        System.out.println(manager);
        manager.addUser();
        return "success";
    }
}
  1. applicationContext.xml
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
default-autowire="byName"><!-- 统一注入方式 ,其他地方就近原则 -->
    <!-- 
    autowire="byType":按类型自动注入 ,有相同类型会抛异常 
    autowire="byName":按名称注入 
    autowire="constructor":构造注入,使用参数构造器在创建实例时将目标属性注入, 
    有两个以上相同类型的对象时,如果没有id跟属性名相同的会抛异常 ,有则使用相同的 
    -->
    <bean id="userAction" class="com.alyshen.spring.UserAction"
        scope="singleton" autowire="constructor" />

    <bean id="userManager" class="com.alyshen.spring.UserManager"
        scope="prototype"/>

    <bean id="manager" class="com.alyshen.spring.UserManager" scope="prototype"/>
</beans>
  1. MainClass.java
public static void main(String[] args) {

    BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");

    UserAction ua = (UserAction) factory.getBean("userAction");
    System.out.println(ua);
    System.out.println(ua.execute());
}

通过注解注入

  1. applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/tx 
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
  
    <!-- 
    启用注解注入 
    -->
    <context:annotation-config />

    <bean id="userAction" class="com.alyshen.spring.UserAction"
        scope="singleton" />

    <bean id="userManager" class="com.alyshen.spring.UserManager" scope="prototype"/>
</beans>
  1. UserAction.java
public class UserAction {

    @Resource
    private UserManager manager = null;
    //Set方法都省了
    //  @Resource
    //  public void setManager(UserManager manager) {
    //      System.out.println("调用manager的set方法注入!");
    //      this.manager = manager;
    //  }

    public String execute() {
        System.out.println(manager);
        this.manager.addUser();
        return "success";
    }
}

Spring自动扫描组件

  1. applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" 
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/tx 
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <!-- 
    启用注解注入 
    -->
    <context:annotation-config />

    <!-- 
    启用组件自动扫描 
    -->
    <context:component-scan base-package="com.alyshen.spring" />
</beans>
  1. UserManager.java
@Repository("uManager")
public class UserManager {

    public void addUser() {

        System.out.println("用户管理执行添加User对象的操作!");

    }
}
  1. UserService.java
@Service("uService")
public class UserService {

    @Resource(name = "uManager")
    private UserManager manager;

    public void service() {
        System.out.println("调用Service");
        manager.addUser();
    }
}
  1. UserAction.java
@Controller("uAction")
//@Scope("prototype") //多例
public class UserAction {

    @Resource(name = "uService")
    private UserService service;

    public String execute() {
        System.out.println("调用Action");
        service.service();
        return "success";
    }
}
  1. MainClass.java
public static void main(String[] args) {

    BeanFactory factory = new ClassPathXmlApplicationContext(
            "applicationContext.xml");

    // UserAction ua = (UserAction) factory.getBean("userAction");

    UserAction ua = (UserAction) factory.getBean("uAction");
    System.out.println(ua);

    ua = (UserAction) factory.getBean("uAction");
    System.out.println(ua);

    ua = (UserAction) factory.getBean("uAction");
    System.out.println(ua);

    System.out.println(ua.execute());
}

关注点分离和静态代理

  1. 关注点分离
Me.java
@Component
public class Me {

    @Resource
    private Servant servant;

    public void dowork() {

        makeBeds();// 关注点
        dress();// 关注点
        haveAMeal();// 关注点

        System.out.println("我工作……");// 真正的业务

        haveAMeal();// 关注点
        makeBeds();// 关注点
        undress();// 关注点

    }

    // 使用面向过程编程
    private void makeBeds() {
    System.out.println("叠被子");
    }

    private void dress() {
    System.out.println("穿衣服");
    }

    private void haveAMeal() {
    System.out.println("吃饭");
    }

    private void undress() {
    System.out.println("脱衣服");
    }
}
  1. 静态代理 a) MeInterface.java
public interface MeInterface {

    public abstract void dowork();
}

b) Me.java

@Component("me")
public class Me implements MeInterface {
    @Override
    public void dowork() {

        System.out.println("我工作……");// 真正的业务
    }
}

c) Servant.java

@Component("ser")
public class Servant {
    public void work1() {
        this.makeBeds();
        this.dress();
        this.haveAMeal();
    }

    public void work2() {
        this.haveAMeal();
        this.puChuang();
        this.undress();
    }

    public void makeBeds() {
        System.out.println("叠被子");
    }

    public void dress() {
        System.out.println("穿衣服");
    }

    public void haveAMeal() {
        System.out.println("吃饭");
    }

    public void undress() {
        System.out.println("脱衣服");
    }

    public void puChuang() {
        System.out.println("铺床");
    }
}

d) MyProxy.java

@Component
public class MyProxy implements MeInterface {

    @Resource(name = "me")
    private Me target;// 真正的目标对象,我们这个代理服务的对象

    @Resource(name="ser")
    private Servant servant;

    @Override
    public void dowork() {

        servant.work1();

        target.dowork();

        servant.work2();
    }
}

e) 使用代理

@Test
public void test() {

    BeanFactory factory = new ClassPathXmlApplicationContext(
            "applicationContext.xml");
    
    MeInterface me = (MeInterface) factory.getBean(MyProxy.class);
    //代理将我的关注点做好再让我去工作……
    me.dowork();
}

动态代理和横切关注点分离

  1. DynamicProxyFactory.java
public class DynamicProxyFactory implements InvocationHandler {

    private DynamicProxyFactory() {
    }

    // 自己new的没法注入,通过创建代理的newInstance方法注入
    private Servant servant;
    private Object target;

    /**
     * 创建代理的静态方法
     */
    public static Object newInstance(Object target, Servant servant) {
        DynamicProxyFactory dp = new DynamicProxyFactory();
        dp.servant = servant;
        dp.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), dp);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        servant.work1();

        Object o = // 调用动态代理类代理的目标对象上的方法(真正要调用的业务方法)
        method.invoke(target, args);

        servant.work2();
        return o;
    }
}
  1. applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/tx 
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
   
    <!-- 启用注解注入 -->
    <context:annotation-config />

    <!-- 启用组件扫描 -->
    <context:component-scan base-package="com.ashmit.spring" />

    <bean id="my" class="com.ashmit.spring.DynamicProxyFactory"
        factory-method="newInstance">
        <constructor-arg ref="me" /> 
        <constructor-arg ref="ser" /> 
    </bean>
        <bean id="h" class="com.ashmit.spring.DynamicProxyFactory"
        factory-method="newInstance">
        <constructor-arg ref="he" /> 
        <constructor-arg ref="ser" /> 
    </bean>
</beans>
  1. 使用动态代理
@Test
public void test() {
    BeanFactory factory = new ClassPathXmlApplicationContext(
            "applicationContext.xml");
    
    MeInterface me = (MeInterface) factory.getBean("my");
    //代理将我的关注点做好再让我去工作……
    me.dowork();
    
    System.out.println("--------------------");
    HeInterface he = (HeInterface) factory.getBean("h");
    he.hedowork();
}

利用Spring的AspectJ创建动态代理分离横切关注点

  1. 用到的包
    aspectjrt.jar   Spring的依赖包
    aspectjweaver.jar   Spring的依赖包
    aopalliance.jar aop
    spring-aop-3.2.0.M1.jar aop支持类
  1. applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/tx 
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- 启用注解注入 -->
    <context:annotation-config />

    <!-- 启用组件扫描 -->
    <context:component-scan base-package="com.ashmit.spring" />

    <!-- 启用asppectj -->
    <aop:aspectj-autoproxy />
</beans>
  1. AspClass.java
/**
* 切面类
*/
@Aspect
@Component
public class AspClass {

    @Resource(name = "ser")
    private Servant servant;

    @Before("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    void before() {
        servant.work1();
    }

    @After("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    void after() {
        servant.work2();
    }
}
  1. 使用Spring的AspectJ创建的动态代理
@Test
public void test() {
    BeanFactory factory = new ClassPathXmlApplicationContext(
            "applicationContext.xml");
    
    MeInterface me = (MeInterface) factory.getBean("me");
    //代理将我的关注点做好再让我去工作……
    me.dowork();
    
    System.out.println("--------------------");
    HeInterface he = (HeInterface) factory.getBean("he");
    he.hedowork();
}
  1. 可以不使用切面类AspClass a) Servant01
@Aspect
@Component
public class Servant01 implements Ordered {

    @Before("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    public void makeBeds() {
        System.out.println("叠被子");
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

b) Servant02

@Aspect
@Component
public class Servant02 implements Ordered{

    @Before("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    public void dress() {
        System.out.println("穿衣服");
    }

    @Override
    public int getOrder() {
        // TODO Auto-generated method stub
        return 1;
    }
}

c) Servant03

@Aspect
@Component
public class Servant03 implements Ordered {

    @Before("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    public void haveAMeal() {
        System.out.println("吃饭");
    }

    @After("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    public void haveAMeal2() {
        System.out.println("吃饭");
    }

    @Override
    public int getOrder() {
        // TODO Auto-generated method stub
        return 2;
    }
}

d) Servant04

@Aspect
@Component
public class Servant04 implements Ordered{

    @After("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    public void puChuang() {
        System.out.println("铺床");
    }

    @Override
    public int getOrder() {
        // TODO Auto-generated method stub
        return 1;
    }
}

e) Servant05

@Aspect
@Component
public class Servant05 implements Ordered{

    @After("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    public void undress() {
        System.out.println("脱衣服");
    }

    @Override
    public int getOrder() {
        // TODO Auto-generated method stub
        return 0;
    }
}
  1. Around、AfterThrowing等其它Advice a) Me.java
@Component("me")
public class Me implements MeInterface {

    @Override
    public void dowork() {
        if (true)
            throw new RuntimeException("RuntimeException……");
        System.out.println("我工作……");// 真正的业务
    }
}

b) AspClass.java

/**
* 切面类
*/
@Aspect
@Component
public class AspClass {

    @Resource(name = "ser")
    private Servant servant;

    /**
     * @param 执行方法的东西
     * @return 返回方法的返回值
     */
        //  @Around("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
        //  public Object test(ProceedingJoinPoint proceeding) {
        //      Object o = null;
        //      try {
        //          servant.work1();
        //          // proceeding.proceed(proceeding.getArgs());
        //          o = proceeding.proceed();
        //          
        //          servant.work2();
        //      } catch (Throwable e) {
        //          // TODO Auto-generated catch block
        //          e.printStackTrace();
        //      }
        //      return o;
        //  }


    @Before("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    void before() {
        System.out.println("开始代理……");
        servant.work1();
    }
    @After("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    void after() {
        servant.work2();
        System.out.println("结束代理……");
    }
    /**
     * 返回时执行(最后执行)
     */
    @AfterReturning("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    void test2() {
        System.out.println("返回……");
    }

    /**
     * 抛异常 注意:不能跟定义了@Around的方法连着用,否则不执行
     */
    @AfterThrowing("execution(* com.ashmit.spring.MeInterface.*(..))||execution(* com.ashmit.spring.HeInterface.*(..))")
    void test3() {
        System.out.println("抛异常……");
    }
}

Spring配置文件中配置切面

  1. AspClass.java
/**
* 切面类
*/
@Component("aspclass")
public class AspClass {

    @Resource(name = "ser")
    private Servant servant;

    void before() {
        servant.work1();
    }

    void after() {
        servant.work2();
    }
}
  1. applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" 
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/tx 
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- 启用注解注入 -->
    <context:annotation-config />

    <!-- 启用组件扫描 -->
    <context:component-scan base-package="com.ashmit.spring" />

    <!-- 启用asppectj 
    <aop:aspectj-autoproxy /> 
    -->

    <aop:config>
        <!-- 切入点 -->
        <aop:pointcut
            expression="execution(* com.ashmit.spring.MeInterface.*(..))
    ||execution(* com.ashmit.spring.HeInterface.*(..))"
            id="mypc" />

        <!-- 通知 -->
        <aop:aspect ref="aspclass">
            <aop:before method="before" pointcut-ref="mypc" />
        </aop:aspect>
        <aop:aspect ref="aspclass">
            <aop:after method="after" pointcut-ref="mypc" />
        </aop:aspect>

    </aop:config>
</beans>

Spring AOP声明式事务

  1. 用到的包
    commons-dbcp.jar    
    commons-pool.jar    
    spring-jdbc-3.2.0.M1.jar    以上dataSource需要
    spring-orm-3.2.0.M1.jar sessionFactory需要
    spring-aop-3.2.0.M1.jar aop支持类
    spring-tx-3.2.0.M1.jar  事物通知
  1. applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/tx 
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- 启用注解注入 -->
    <context:annotation-config />

    <!-- 启用组件扫描 -->
    <context:component-scan base-package="com.ashmit" />

    <!-- 数据源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"

        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url"
            value="jdbc:mysql://127.0.0.1:3306/ssh?createDatabaseIfNotExist=true" />
        <property name="username" value="root" />
        <property name="password" value="654321" />
    </bean>

    <!-- Spring的sessionFactory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.ashmit.entity.User</value>
                <value>com.ashmit.entity.Group</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
                hibernate.show_sql=true
                hbm2ddl.auto=update
                javax.persistence.validation.mode=none
                hibernate.cache.use_second_level_cache=true
                hibernate.cache.use_query_cache=true
    hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
            </value>
        </property>
    </bean>

    <!-- 事物管理器 -->
    <bean id="txManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <!-- 事物通知 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- the transactional semantics... -->
        <tx:attributes>
            <!-- all method starting with 'get' are read-only -->
            <tx:method name="get*" read-only="true" />
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>

    <!-- 事物管理切面 -->
    <aop:config>
        <aop:pointcut id="fooServiceOperation"
            expression="execution(* com.ashmit.service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation" />
    </aop:config>
</beans>
  1. 事务传播特性
<!-- 事务通知 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <!-- the transactional semantics... -->
    <tx:attributes>
        <!-- all method starting with 'get' are read-only -->
        <!-- 
        read-only="true":相当于:   this.getSession().setFlushMode(FlushMode.MANUAL);
            MANUAL:只能执行只读事务,不刷新
            COMMIT:提交时发出查询
            AUTO:默认,如果有增删改,会判断你在缓存里查询的是不是脏数据,是:不让刷新
            ALWAYS:与AUTO不同的是:不判断,直接刷新,可能会读取到脏数据
         -->
        <tx:method name="find*" read-only="true" />
        
        <!-- other methods use the default transaction settings (see below) -->
        <!-- 
        isolation:隔离级别
        propagation:事物的传播特性
            REQUIRED:默认,使用同一个事务,没有会创建
            REQUIRES_NEW:开启新事务
            NEVER:永远不在事务里执行
            NESTED:嵌套事务,设置了事务保存点,提交回滚不影响其他事务,
                对Hibernate不起作用,只对数据源(dataSource)作用
            NOT_SUPPORTED:不在事务里执行,如果已开启事物,这个事务会挂起
            SUPPORTS:已开启事务就使用,没有开启事务就在没有事务环境下执行
            MANDATORY:必须在已开启事务的环境下运行,没有开启就抛异常
        -->
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

Spring与Struts框架的集成

  1. 用到的包
struts2-spring-plugin-2.3.4.jar 在Struts文件中
spring-web-3.2.0.M1.jar 在Spring文件中
  1. UserAction.java
@Controller("userAction")
public class UserAction implements ModelDriven {

    private User user = null;

    @Resource(name = "groupService")
    private GroupService groupService = null;

    @Resource(name = "userService")
    private UserService userService = null;

    //各种方法
    ……
}
  1. web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">

    <!-- 创建sessionFactory并将其置入ServletContext当中的监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 指定Spring工厂配置文件所在路径的全局参数,ContextLoaderListener专用 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml</param-value>
    </context-param>

    ……
</web-app>

BaseDao模式

  1. BaseDao.java
public class BaseDao {

    @Resource(name = "sessionFactory")
    private SessionFactory sessionFactory = null;

    protected Session getSession() {
        return this.sessionFactory.getCurrentSession();
    }
}

OpenSessionInView模式

应对懒加载策略

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">

    <!-- 创建sessionFactory并将其置入ServletContext当中的监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 指定Spring工厂配置文件所在路径的全局参数,ContextLoaderListener专用 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml</param-value>
    </context-param>

    <!-- 启用尽早打开尽可能晚关闭session的filter -->
    <filter>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    ……
</web-app>

猜你喜欢

转载自www.cnblogs.com/yhongyin/p/12004406.html
今日推荐