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>
posted @ 2019-12-08 04:05  Aick  阅读(240)  评论(0编辑  收藏  举报