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>
- 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"));
}
构造注入及注意事项
- 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方法
……
}
- 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>
- 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());
}
- 注意事项
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>
自动注入及注意事项
- UserManager.java
public class UserManager {
public void addUser() {
System.out.println("添加用户!");
}
}
- 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";
}
}
- 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>
- 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());
}
通过注解注入
- 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>
- 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自动扫描组件
- 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>
- UserManager.java
@Repository("uManager")
public class UserManager {
public void addUser() {
System.out.println("用户管理执行添加User对象的操作!");
}
}
- UserService.java
@Service("uService")
public class UserService {
@Resource(name = "uManager")
private UserManager manager;
public void service() {
System.out.println("调用Service");
manager.addUser();
}
}
- 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";
}
}
- 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());
}
关注点分离和静态代理
- 关注点分离
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("脱衣服");
}
}
- 静态代理
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();
}
动态代理和横切关注点分离
- 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;
}
}
- 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>
- 使用动态代理
@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创建动态代理分离横切关注点
- 用到的包
aspectjrt.jar Spring的依赖包
aspectjweaver.jar Spring的依赖包
aopalliance.jar aop
spring-aop-3.2.0.M1.jar aop支持类
- 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>
- 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();
}
}
- 使用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();
}
- 可以不使用切面类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;
}
}
- 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配置文件中配置切面
- AspClass.java
/**
* 切面类
*/
@Component("aspclass")
public class AspClass {
@Resource(name = "ser")
private Servant servant;
void before() {
servant.work1();
}
void after() {
servant.work2();
}
}
- 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声明式事务
- 用到的包
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 事物通知
- 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>
- 事务传播特性
<!-- 事务通知 -->
<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框架的集成
- 用到的包
struts2-spring-plugin-2.3.4.jar 在Struts文件中
spring-web-3.2.0.M1.jar 在Spring文件中
- 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;
//各种方法
……
}
- 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模式
- 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>