public interface UserDAO { public void save(User user); } public class UserDAOImpl implements UserDAO { public void save(User user) { //Hibernate //JDBC //XML //NetWork
System.out.println("user saved!"); } } public class UserService { private UserDAO userDAO; public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } }
<!--beans.xml -->
<beans>
<bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl" />
<bean id="userService" class="com.bjsxt.service.UserService" >
<property name="userDAO" bean="u"/>
</bean>
</beans>
public interface BeanFactory { public Object getBean(String id); } public class ClassPathXmlApplicationContext implements BeanFactory { private Map<String , Object> beans = new HashMap<String, Object>(); //IOC Inverse of Control DI Dependency Injection
public ClassPathXmlApplicationContext() throws Exception { //解析xml的一套api
SAXBuilder sb=new SAXBuilder(); Document doc=sb.build(this.getClass().getClassLoader().getResourceAsStream("beans.xml"));
Element root=doc.getRootElement(); //获取根元素HD
List list=root.getChildren("bean");//取名字为disk的所有元素
for(int i=0;i<list.size();i++){ Element element=(Element)list.get(i); String id=element.getAttributeValue("id"); String clazz=element.getAttributeValue("class"); Object o = Class.forName(clazz).newInstance(); System.out.println(id); System.out.println(clazz); beans.put(id, o); for(Element propertyElement : (List<Element>)element.getChildren("property")) { String name = propertyElement.getAttributeValue("name"); //userDAO
String bean = propertyElement.getAttributeValue("bean"); //u
Object b = beans.get(bean);//UserDAOImpl instance
String methodName="set"+name.substring(0, 1).toUpperCase()+name.substring(1); Method m = o.getClass().getMethod(methodName, b.getClass().getInterfaces()[0]); m.invoke(o, b); } } } public Object getBean(String id) { return beans.get(id); } }
//引入的是我们自己的
import com.bjsxt.model.User; import com.bjsxt.spring.BeanFactory; import com.bjsxt.spring.ClassPathXmlApplicationContext; public class UserServiceTest { @Test public void testAdd() throws Exception { BeanFactory applicationContext = new ClassPathXmlApplicationContext(); UserService service = (UserService)applicationContext.getBean("userService"); User u = new User(); u.setUsername("zhangsan"); u.setPassword("zhangsan"); service.add(u); } }
ps:这要在之前的话,要写两个工厂类DaoFactory和ServiceFactory,还要写两个配置文件dao.properties和service.properties.现在只要一个beans.xml就可实现之前的功能,实现完全解耦,简化开发.
<!--beans.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-2.5.xsd">
<bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl"></bean>
<bean id="userService" class="com.bjsxt.service.UserService">
<property name="userDAO" ref="u" /> <!--将我们模拟的bean改为ref -->
</bean>
</beans>
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.bjsxt.model.User; //Dependency Injection //Inverse of Control
public class UserServiceTest { @Test public void testAdd() throws Exception { //将我们的BeanFactory改为ApplicationContext //ApplicationContext实现了BeanFactory,spring建议使用ApplicationContext,功能更多
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); User u = new User(); u.setUsername("zhangsan"); u.setPassword("zhangsan"); service.add(u); } }
ps:IOC(DI),有什么好处:1、把自己new的东西改为由容器提供,初始化具体值,装配.2、好处:灵活装配.
1、注入的类型
setter注入,即提供set、get方法的注入,,构造方法注入,了解,例:
<bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl"></bean>
<bean id="userService" class="com.bjsxt.service.UserService">
<constructor-arg>
<ref bean="u" /> <!--写bean和=号一样 -->
</constructor-arg>
</bean>
public class UserService { private UserDAO userDAO; public UserService(UserDAO userDAO) { super(); this.userDAO = userDAO; } }
2、bean的id和name
<?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-2.5.xsd">
<!--id,name没什么区别,就是name可以特殊字符,但谁没事这么干 -->
<bean name="u" class="com.bjsxt.dao.impl.UserDAOImpl"></bean>
<bean id="userService" class="com.bjsxt.service.UserService">
<property name="userDAO" ref="u" />
</bean>
</beans>
public class UserService { private UserDAO userDAO; public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } }
public class UserServiceTest { @Test public void testAdd() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); User u = new User(); u.setUsername("zhangsan"); u.setPassword("zhangsan"); service.add(u); } }
3、简单属性的注入
<?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-2.5.xsd">
<!--简单属性注入 ,value和ref用子标签和属性都可以 -->
<bean name="userDAO" class="com.bjsxt.dao.impl.UserDAOImpl">
<property name="daoId" value="8"></property>
<property name="daoStatus" value="good"></property>
</bean>
<bean id="userService" class="com.bjsxt.service.UserService">
<property name="userDAO" ref="userDAO" />
</bean>
</beans>
public class UserDAOImpl implements UserDAO { private int daoId; private String daoStatus; public int getDaoId() { return daoId; } public void setDaoId(int daoId) { this.daoId = daoId; } public String getDaoStatus() { return daoStatus; } public void setDaoStatus(String daoStatus) { this.daoStatus = daoStatus; } @Override public String toString() { return this.daoId + ":" + this.daoStatus; } }
4、bean中的scope属性
<?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-2.5.xsd">
<bean name="u" class="com.bjsxt.dao.impl.UserDAOImpl"></bean>
<!--bean生命范围,singel单例(默认),prototype每次按这个原型造一个,比如是个action的话要用prototype-->
<!--和web相关的request,session,application等很少用,因为没必要,我们在action中可以很方便的放进去 -->
<bean id="userService" class="com.bjsxt.service.UserService" scope="prototype">
<property name="userDAO" ref="u" />
</bean>
</beans>
public class UserServiceTest { @Test public void testAdd() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); UserService service2 = (UserService)ctx.getBean("userService"); System.out.println(service == service2);//false
} }
5、集合注入
public class UserDAOImpl implements UserDAO { //提供set、get方法
private Set<String> sets; private List<String> lists; private Map<String , String> maps; }
<?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-2.5.xsd">
<!--如果集合中类的话,参见之前的ref -->
<bean name="userDAO" class="com.bjsxt.dao.impl.UserDAOImpl">
<property name="sets">
<set>
<value>1</value>
<value>2</value>
</set>
</property>
<property name="lists">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<property name="maps">
<map>
<entry key="1" value="1"></entry>
<entry key="2" value="2"></entry>
<entry key="3" value="3"></entry>
<entry key="4" value="4"></entry>
</map>
</property>
</bean>
</beans>
6、autowire自动装配
<?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-2.5.xsd" default-autowire="byName"><!--还可以在这里指定 -->
<bean name="userDAO" class="com.bjsxt.dao.impl.UserDAOImpl">
<property name="daoId" value="1"></property>
</bean>
<bean name="userDAO2" class="com.bjsxt.dao.impl.UserDAOImpl">
<property name="daoId" value="2"></property>
</bean>
<!--最常用两个byName和byType(default是beans标签里的default-autowire),下面这个会报错,expect 1 found 2 -->
<bean id="userService" class="com.bjsxt.service.UserService" autowire="byType"></bean>
</beans>
public class UserService { private UserDAO userDAO; public UserDAO getUserDAO() { return userDAO; } public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } }
7、生命周期
<?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-2.5.xsd">
<bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl"></bean>
<!--默认情况下只要ClassPathXmlApplicationContext new出来,这个xml文件中的bean就全部初始化了 -->
<!--加lazy-init="true"后,容器初始化的不进行初始化,用到(getBean)的时候初始化,这种用在启动特别慢的时候 -->
<!--beans标签可以全部设置为 lazy-init="true"和之前beans里设置默认default-autowire道理一样 -->
<!--init-method="init" destroy-method="destroy" 和servlet类似,scope="prototype"每次都调用,single只调用一次-->
<bean id="userService" class="com.bjsxt.service.UserService" init-method="init" destroy-method="destroy" scope="prototype" lazy-init="true">
<property name="userDAO" ref="u" />
</bean>
</beans>
public class UserService { private UserDAO userDAO; public void init() { System.out.println("init"); } public UserDAO getUserDAO() { return userDAO; } public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } public void destroy() { System.out.println("destroy"); } }
1、@Autowired、@Qualifier
<?xml version="1.0" encoding="UTF-8"?>
<!--加xmlns:context这个namespace -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!--初始化一些bean处理程序中的注解,默认byType -->
<context:annotation-config />
<!--使用@Autowired的双方必须交给spring bean工厂来管理 -->
<bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl"></bean>
<bean id="u2" class="com.bjsxt.dao.impl.UserDAOImpl"></bean>
<bean id="userService" class="com.bjsxt.service.UserService"></bean>
</beans>
public class UserService { private UserDAO userDAO; public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } //@Autowired按byType查找,不写这个@Qualifier("u")报错,extend 1 found 2 //@Qualifier("u")指定按id和name查找 //@Autowired(required=false),不是必须的,也就是不注入也可以
@Autowired public void setUserDAO(@Qualifier("u") UserDAO userDAO) { this.userDAO = userDAO; } }
2、@Required
public class UserService { private UserDAO userDAO; public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } //@Required必须注入的,容错用的类似@Override,编译器就会发现错误
@Required public void setUserDAO(@Qualifier("u") UserDAO userDAO) { this.userDAO = userDAO; } }
3、@Resource
public class UserService { private UserDAO userDAO; //建议使用这个,不写name是byType,@Resource(name="u")写name后按byName
@Resource public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } public UserDAO getUserDAO() { return userDAO; } }
4、@Component @Service @Controller @Repository
简化配置,当bean很多时,无需一一在bean.xml中配置.
@Component("u") public class UserDAOImpl implements UserDAO { public void save(User user) { //Hibernate //JDBC //XML //NetWork
System.out.println("user saved!"); } }
//本意是在持久性,业务层和表示层分别为@Repository、@Service和@Controller,但是目前和@Component没有区别
@Component("userService") public class UserService { private UserDAO userDAO; public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } @Resource(name="u") public void setUserDAO( UserDAO userDAO) { this.userDAO = userDAO; } }
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<!--在ClassPathXmlApplicationContext初始化的时候,读beans.xml,发现<context:component-scan>后去相应包下扫描所有的类, 看看你类上有没有@Component,有的话就相当于在这里定义的bean一样,创建一个这个类的对象,key是@Component("u")这个名字"u", value是这个创建的对象,没写名字的话key是类名首字母改小写 -->
<context:component-scan base-package="com.bjsxt" />
</beans>
5、@Scope @PostConstruct @PreDestroy
//@PostConstruct,@PreDestroy等价于xml中的init-method="init" destroy-method="destroy" //@Scope("prototype")等价于xml bean中的scope
@Scope("prototype") @Component("userService") public class UserService { private UserDAO userDAO; @PostConstruct public void init() { System.out.println("init"); } public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } @Resource(name="u") public void setUserDAO( UserDAO userDAO) { this.userDAO = userDAO; } @PreDestroy public void destroy() { System.out.println("destroy"); } }
<!--bean.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="com.bjsxt"/>
</beans>
public class UserServiceTest { @Test public void testProxy() { UserDAO userDAO = new UserDAOImpl(); LogInterceptor li = new LogInterceptor(); li.setTarget(userDAO); // 基于实现接口的,也就是接口里面有几个方法,代理里就有几个方法
UserDAO userDAOProxy = (UserDAO) Proxy.newProxyInstance(userDAO .getClass().getClassLoader(), userDAO.getClass() .getInterfaces(), li); System.out.println(userDAOProxy.getClass()); userDAOProxy.delete(); userDAOProxy.save(new User()); } }
public class LogInterceptor implements InvocationHandler { private Object target; public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public void beforeMethod(Method m) { System.out.println(m.getName() + " start"); } public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { beforeMethod(m); m.invoke(target, args); return null; } }
ps:动态代理参考jdbc数据库连接那节.
public class UserServiceTest { @Test public void testAdd() throws Exception { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); System.out.println(service.getClass());//cglib的代理对象 //因为UserService没有实现接口,实现接口的话会用jdk产生代理,如果没有实现接口会默认采用CGlib产生代理对象
service.add(new User());//这里会报错,提示cglib在ClassPath中没有 ctx.destroy(); } }
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" <!--要加这个namespace --> xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <context:annotation-config />
<context:component-scan base-package="com.bjsxt"/>
<!--写上这个标签的意思就是可以使用aspectj注解的方式来去定义spring的aop-->
<!--aop的注解需要aspectj这个类库,aspectj专门产生各种动态代理的面向切面的框架-->
<!--ClassPathXmlApplicationContext new 出来的时候也可以说容器启动的时候有需要产生代理的类就会产生代理-->
<aop:aspectj-autoproxy />
</beans>
@Component("userService") public class UserService { private UserDAO userDAO; public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } @Resource(name="u") public void setUserDAO( UserDAO userDAO) { this.userDAO = userDAO; } }
@Component("u") public class UserDAOImpl implements UserDAO { public void save(User user) { System.out.println("user saved!"); } }
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; //大多数情况用不着spring自己的aop语法,用aspectj就可 //aop代理的那个对象必须是spring管理起来的,自己new的不行,切面类本身LogInterceptor也必须交给spring管理
@Aspect @Component public class LogInterceptor { //织入点语法:@Before前 @AfterReturning后 @AfterThrowing抛出异常后 @after等价于finally @Around环绕
@Pointcut("execution(public * com.bjsxt.service..*.add(..))") public void myMethod(){};//给这个Pointcut起个名字 //一般应该这么来写,上面的方法提取出了Pointcut,用来共用
/*@Before("execution(public * com.bjsxt.service..*.add(..))") public void before() { System.out.println("method before"); }*/
//@Before在前还是@Around在前呢,不要依赖于他们前后顺序,用时可以写在一起加一个就可
@Before("myMethod()") public void before() { System.out.println("method before"); } @Around("myMethod()") public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println("method around start"); pjp.proceed(); //和拦截器的责任链一样
System.out.println("method around end"); } }
相对于Annotation来说,UserServiceTest 、UserService、UserDAOImpl全部不变,只需修改配置文件bean.xml和LogInterceptor.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="com.bjsxt"/>
<!--xml要掌握,因为很多时候是人家的代码,我们不能在人家的源码上加注解,这个时候要采用xml -->
<!--xml就不需要<aop:aspectj-autoproxy /> -->
<aop:config>
<aop:aspect id="logAspect" ref="logInterceptor">
<aop:before method="before" pointcut="execution(public * com.bjsxt.service..*.add(..))" />
</aop:aspect>
</aop:config>
<!-- <aop:pointcut expression="" id=""/>用来定义全局的 -->
<aop:config>
<aop:pointcut expression="public * com.bjsxt.service..*.add(..)" id="servicePointCut"/>
<aop:aspect id="logAspect2" ref="logInterceptor">
<aop:before method="before" pointcut-ref="servicePointCut"/>
</aop:aspect>
</aop:config>
</beans>
@Component public class LogInterceptor { public void before() { System.out.println("method before"); } public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println("method around start"); pjp.proceed(); System.out.println("method around end"); } }
ps:DI使用annotation较多,AOP使用XML较多.
1、spring dataSource的配置
public interface UserDAO { public void save(User user); }
@Component("u") public class UserDAOImpl implements UserDAO { private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } @Resource public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public void save(User user) { System.out.println("session factory class:" + sessionFactory.getClass()); Session s = sessionFactory.openSession(); s.beginTransaction(); s.save(user); s.getTransaction().commit(); System.out.println("user saved!"); } }
@Component("userService") public class UserService { private UserDAO userDAO; public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } @Resource(name="u") public void setUserDAO( UserDAO userDAO) { this.userDAO = userDAO; } }
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="com.bjsxt" />
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:jdbc.properties</value>
</property>
</bean>
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!--class一定是实现了hibernate的SessionFactory(接口) -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<!--数组和list都这么注入 -->
<list>
<value>com.bjsxt.model.User</value>
</list>
</property>
<property name="hibernateProperties">
<!--properties的注入方式 -->
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
</beans>
#jdb.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=bjsxt
public class UserServiceTest { @Test public void testAdd() throws Exception { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); System.out.println(service.getClass()); service.add(new User()); ctx.destroy(); } }
ps:dataSource可以配置在spring中也可以配置hibernate中,但大多数是通过JNDI注册在在application Server中的.
面试题:dataSource在高并发下连接数量的设置,这个的影响因素有很多,cpu、内存、webserver性能、每个连接时间长短、负载均衡,正确的方法是用多线程活工具测试下,或者写多线程程序测试每次web请求的相应时间是否在可以接受的范围内.
2、使用Annotation进行声明式事务管理
public interface LogDAO { public void save(Log log); } public interface UserDAO { public void save(User user); } @Component("logDAO") public class LogDAOImpl implements LogDAO { private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } @Resource public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public void save(Log log) { //这里不能openSession了,只能getCurrentSession,验证了确实是在ThreadLoacl中放了Connection
Session s = sessionFactory.getCurrentSession(); s.save(log); } } @Component("u") public class UserDAOImpl implements UserDAO { private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } @Resource public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public void save(User user) { Session s = sessionFactory.getCurrentSession(); s.save(user); //throw new RuntimeException("exeption!");会自动回滚,编译时异常的话要在service中try catch
} }
<!--bean.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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" <!--要加这个namespace --> xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <context:annotation-config />
<context:component-scan base-package="com.bjsxt" />
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:jdbc.properties</value>
</property>
</bean>
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.bjsxt.model.User</value>
<value>com.bjsxt.model.Log</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!--HibernateTransactionManager这个其实就是个切面类,如果是jta的话是TransactionManager这个类 -->
<!--其实txManager也是在ThreaLocal中放了Connection -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<!--通过数据库连接来管理事务,所以通过注入sessionFactory的方式 ,txManager也需要hibernate的那些配置 -->
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
@Component("userService") public class UserService { private UserDAO userDAO; private LogDAO logDAO; //这里捕捉到异常的话会自动回滚 //@Transactional就是典型的AOP,前面加了开启事务,结尾加了关闭事务,加了try catch finally roalback... //@Transactional(propagation = Propagation.REQUIRED),如果有别的方法调用add,并且也开启事务的话,那么就共用一个事务,如果没有的话,我就新开启一个事务,也是默认值,Propagation(中文传播的意思)还包括一些回滚点什么也属于Propagation的属性用的不多 //@Transactional(readOnly = true)下面这句会报错,不能插入 Connection是read only,read only的Connection执行效率较高,这个就是用来提高性能的
@Transactional(readOnly = true) public void add(User user) { userDAO.save(user); Log log = new Log(); log.setMsg("a user saved!"); logDAO.save(log); } public UserDAO getUserDAO() { return userDAO; } @Resource(name = "u") public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } @Resource public void setLogDAO(LogDAO logDAO) { this.logDAO = logDAO; } public User getUser(int id) { return null; } public LogDAO getLogDAO() { return logDAO; } }
public class UserServiceTest { @Test public void testAdd() throws Exception { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); System.out.println(service.getClass()); service.add(new User()); ctx.destroy(); } }
@Transactional属性配置
3、使用XML进行声明式事务管理,只需bean.xml改为如下,UserService add方法无需加注解:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="com.bjsxt" />
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:jdbc.properties</value>
</property>
</bean>
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">//扫描实体类,简化开发
<list>
<value>com.bjsxt.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<aop:config>
<aop:pointcut id="bussinessService" expression="execution(public * com.bjsxt.service..*.*(..))" />
<aop:advisor pointcut-ref="bussinessService" advice-ref="txAdvice" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="add*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
</beans>
4、hibernateTemplate
@Component("u") public class UserDAOImpl implements UserDAO { private HibernateTemplate hibernateTemplate; public HibernateTemplate getHibernateTemplate() { return hibernateTemplate; } @Resource public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate = hibernateTemplate; } public void save(User user) { hibernateTemplate.save(user); } }
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
ps:原理和springJDBC一样,之前使用hibernate的方式和原始jdbc的方式一模一样,现在大大简化了开发,HibernateDaoSupport略.
1、struts2和spring的整合要加如一个Struts2_Spring_Plugin包.
2、action是客户端访问的时候struts2 new出来的,这个是在struts的容器中而不是在spring的容器中,也就是action无需配置在spring的bean中,完全由struts2自己控制.
3、vo(DTO),用来传数据,分页应用中最典型,客户端提交到一个VO中,返回页面的时候包装到另一个VO中.
4、could not initialize proxy - no Session的错误,这是由于懒加载的时候,直到session已经关闭了,还没有用到直到后面传到jsp页面才用到,才发sql,就会报这个错.
5、没有加事务的话,默认是dao中,因为hibernateTemplete中开启和关闭了事务.
6、中文乱码问题,sturst配常量即可,web.xml写filter也可.
7、struts2配置文件中加:<action name="u" class="u">这么写的话就是从spring容器中取,action头上就必须写@Component("u"),千万不要忘@Scope("prototype").感觉没人这么用.
ps:整个的代码见文件,所有的一切,不确定的时候动手试.