Spring
主要内容:
- 面向接口(抽象)编程的概念与好处
- IOC/DI的概念与好处
a) inversion of control
b) dependency injection
- AOP的概念与好处
- Spring简介
- Spring应用IOC/DI(重要)
a) xml
b) annotation
- Spring应用AOP(重要)
a) xml
b) annotation
- Struts2.1.6 + Spring2.5.6 + Hibernate3.3.2整合
a) opensessionInviewfilter(记住,解决什么问题,怎么解决)
- Spring JDBC
- 场景:用户添加
- 好处:灵活
- 把自己new的东西改为由容器提供
面向接口编程(面向抽象编程)
IOC(DI) 的好处
a) 初始化具体值
b) 装配
- 好处:灵活装配
- FAQ:不给提示:
Spring IOC配置与应用
a) window – preferences – myeclipse – xml – xml catalog
b) User Specified Entries – add
i. Location: spring-beans-2.5.xsd
ii. URI: spring-beans-2.5.xsd
iii. Key Type: Schema Location
iv. Key: http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
- 注入类型
a) Spring_0300_IOC_Injection_Type
b) setter(重要)
c) 构造方法(可以忘记)
d) 接口注入(可以忘记)
- id vs. name
a) Spring_0400_IOC_Id_Name
b) name可以用特殊字符
- 简单属性的注入
a) Spring_0500_IOC_SimpleProperty
b) <property name=… value=….>
- <bean 中的scope属性
a) singleton 单例
b) proptotype 每次创建新的对象
- 集合注入
a) 很少用,不重要!参考程序
- 自动装配
a) byName
b) byType
c) 如果所有的bean都用同一种,可以使用beans的属性:default-autowire
- 生命周期
a) lazy-init (不重要)
b) init-method destroy-methd 不要和prototype一起用(了解)
- Annotation第一步:
a) 修改xml文件,参考文档<context:annotation-config />
10. @Autowired:帮你从容器中找一个相同属性的bean,注入
a) 默认按类型
b) 如果想用byName,使用@Qulifier
c) 写在private field(第三种注入形式)(不建议,破坏封装)
d) 如果写在set上,@qualifier需要写在参数上
@Autowired
public void setUserDAO(
@Qualifier("userdao1")UserDAO userDAO) {
this.userDAO = userDAO;
}
@required是在编译时先检查xml
- @Resource(重要)
a) 加入:j2ee/common-annotations.jar
b) 默认按 名称,名称找不到,按类型
c) 可以指定特定名称
d) 推荐使用
e) 不足:如果没有源码,就无法运用annotation,只能使用
f) 但是这样的话,还是需要在xml文件中去申明bean
使用component就可以让容器在包里自己寻找相应需要注入的bean,而不需要自己手动去配置。
- @Component @Service @Controller @Repository
默认下,会被当做组件被容器所接收
a) 初始化的名字默认为类名首字母小写
b) 可以指定初始化bean的名字
<context:component-scan base-package="xby" />
配置文件会从包里从上向下搜索,遇到@component的类就会将它加入到容器里,同时设置它的key是类名首字母小写
Xml的优势在没有源码的时候,可以在xml里做相应的修改。实际开发中使用注释开发效率高。
Singleton:单例
Prototype:多例
Request
Session
14.构造之后和销毁之前
@PostConstruct = init-method;
@PreDestroy = destroy-method;
什么是AOP
- 面向切面编程Aspect-Oriented-Programming
a) 是对面向对象的思维方式的有力补充
b) 1.写死的话,不便于修改
c) 2.继承父类 extends一旦父类发生变化,子类一定要相应的修改。
d) 3.组合 implement 在实现了相应接口后,可以相互组合。
e) 代理里有哪些方法是根据接口里的方法来的,接口里有哪些方法,代理就有哪些方法。代理对象会把所有的共有接口传进去,顺带把方法和方法的参数一起传进去,然后代理对象会把自己的业务逻辑和被代理对象的方法传进去。代理对象会先执行自己的方法,然后调用自己的invoke方法,这个方法就会调用被代理对象的方法,这就是实现了切面编程。
- Spring_1400_AOP_Introduction
- 好处:可以动态的添加和删除在切面上的逻辑而不影响原来的执行代码
a) Filter
b) Struts2的interceptor
- 概念:
a) JoinPoint:在哪里加入
b) PointCut:joinpoint的集合
c) Aspect(切面):指的是逻辑切面
d) Advice:指的是建议被加入的逻辑
e) Target:被代理对象
f) Weave:织入
代理:只要被代理的对象实现了一个接口,JDK就可以使用InvocationHandler和proxy来完成代理。但是如果被代理对象没有实现了接口,spring就会使用cglib直接操作二进制码来完成代理。
Spring AOP配置与应用
- 两种方式:
a) 使用Annotation
b) 使用xml
- Annotation
a) 加上对应的xsd文件spring-aop.xsd
b) beans.xml <aop:aspectj-autoproxy />
c) 此时就可以解析对应的Annotation了
d) 建立我们的拦截类
e) 用@Aspect注解这个类
f) 建立处理方法
g) 用@Before来注解方法
h) 写明白切入点(execution …….)
i) 让spring对我们的拦截器类进行管理@Component
- 常见的Annotation:
a) @Pointcut
b) @Before
c) @AfterReturning
d) @AfterThrowing
e) @After
f) @Around
- 织入点语法
a) void !void
b) 参考文档(* ..)
- xml配置AOP
a) 把interceptor对象初始化
b) <aop:config
i. <aop:aspect …..
- <aop:pointcut
- <aop:before
---------------------------------------------------------------------------------------
<bean id="Log" class="xby.aop.Log"></bean>-------------------------切面逻辑类
<aop:config>
<aop:pointcut expression="execution(public * xby.dao.impl..*.*(..))" id="servicePointcut" />
<aop:aspect id="LogAspect" ref="Logb">
<aop:before method="before" pointcut-ref="servicePointcut"/>
</aop:aspect>
</aop:config>
在aspect前的pointcut是全局的,可以被所有的aspect使用,而在aspect内部的pointcut是aspect自己的,只能自己用。
Aspect的ref是代表——附加逻辑的代理类
before的point-cut代表的是前面定义好的pointcut。
Pointcut其实就是你可以将附加的逻辑所加到的地方;
Aspect其实就是附加的逻辑切面。
---------------------------------------------------------------------------------------
<bean id="Log" class="xby.aop.Log"></bean>
<aop:config>
<aop:aspect id="LogAspect" ref="Log">
<aop:after method="after" pointcut="execution(public * xby.dao.impl..*.*(..))"/>
</aop:aspect>
</aop:config>
上面的表达也是一样的。
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService service = (UserService)ctx.getBean("userService");
service.add(new User());
程序一开始调用add()-à发现它符合execution(public * xby.dao.impl..*.*(..))
à然后又发现有一个切面aspect-à接着就调用了proxy去做了代理,给它附加了代理逻辑。
Spring整合Hibernate
- Spring 指定datasource
a) 参考文档,找dbcp.BasicDataSource
i. c3p0
ii. dbcp
iii. proxool
b) 在DAO或者Service中注入dataSource
数据源(Data Source)是提供某种所需要数据的器件或原始媒体。顾名思义,数据的来源。在数据源中存储了所有建立数据库连接的信息。就像通过指定文件名称可以在文件系统中找到文件一样,通过提供正确的数据源名称,你可以找到相应的数据库连接。
c) 在Spring中可以使用PropertyPlaceHolderConfigure来读取Properties文件的内容(占位符)
- Spring整合Hibernate
a) <bean .. AnnotationSessionFactoryBean>
i. <property dataSource
ii. <annotatedClasses
b) 引入hibernate 系列jar包
c) User上加Annotation
d) UserDAO或者UserServie 注入SessionFactory
---------------------------------------------------------------------------------------
<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://localhost:3306/spring" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
---------------------------------------------------------------------------------------
<bean id="SessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>xby.model.User</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>
<tx:annotation-driven transaction-manager="txManager"/>
---------------------------------------------------------------------------------------
- 声明式的事务管理
a) 事务加在DAO层还是Service层?
业务逻辑层处理事务不能加在实现层,否则回滚时会出现不一致性。用spring 来做声明式事务管理,就不需要去关心try catch,只需要关心自己的业务逻辑。Spring 会帮你做事务管理,类似回滚之类。
b) annotation
i. 在需要事务的方法上加:@Transactional
ii. 需要注意,使用SessionFactory.getCurrentSession 不要使用OpenSession
---------------------------------------------------------------------------------------
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="SessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
---------------------------------------------------------------------------------------
c) @Transactional详解
i. 什么时候rollback
- 运行期异常,非运行期异常不会触发rollback
- 必须uncheck (没有catch)
- 不管什么异常,只要你catch了,spring就会放弃管理
- 事务传播特性:propagation_required
- read_only
Transactional配置:
Propagation=
- Mandatory:方法执行时必须有一个transaction存在
- Nested:方法执行时在已经存在的transaction中内嵌一个,不影响外部事务;
- Never:不能有事务;
- Not_supported:方法执行时,如果有事务,就给他挂起
- Required:方法执行时,当前有事务就用它,没有就新创建;
- Required_new:方法执行时,如果有事务,就将存在的事务给它挂起,自己重新生成一个新的事务;
- Support:随当前事务,有就有,没有就没有。
ReadOnly=true效率比较高;public void getUser(int id)这时候就可以设置为只读
Rollbackfor:什么情况下回滚,默认为RuntimeException
No Rollbackfor
d) xml(推荐,可以同时配置好多方法)
---------------------------------------------------------------------------------------
<aop:config>
<aop:pointcut expression="execution(public * xby.service..*.*(..))"
id="bussinessService" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="bussinessService" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="getUser" read-only="true" />
<tx:method name="add*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
---------------------------------------------------------------------------------------
e) HibernateTemplate、
HibernateCallback、
HibernateDaoSupport(不重要)
i. 设计模式:Template Method
----------------------------------------------------------------------------------
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="SessionFactory"></property>
</bean>
----------------------------------------------------------------------------------
ii. Callback:回调/钩子函数
iii. 第一种:(建议)
- 在spring中初始化HibernateTemplate,注入sessionFactory
- DAO里注入HibernateTemplate
- save写getHibernateTemplate.save();
iv. 第二种:
- 从HibernateDaoSupport继承
- 必须写在xml文件中,无法使用Annotation,因为set方法在父类中,而且是final的
f) spring整合hibernate的时候使用packagesToScan属性,可以让spring自动扫描对应包下面的实体类
JDBC :
你需要做的第一事情是你与想要使用的 DBMS 建立一个连接。这包含 2 个步骤:装载驱动程序并建立连接。
1)装载驱动
你想要使用 JDBC-ODBC 桥驱动程序, 可以用下列代码装载它:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
你的驱动程序文档将告诉你应该使用的类名。例如, 如果类名是 jdbc.DriverXYZ ,你将用代码以下的代码装载驱动程序:
Class.forName("jdbc.DriverXYZ");
你不需要创建一个驱动程序类的实例并且用 DriverManager 登记它,因为调用 Class.forName 将自动加载驱动程序类。
加载 Driver 类后,它们即可用来与数据库建立连接。
2)建立连接
第二步就是用适当的驱动程序类与 DBMS 建立一个连接。下列代码是一般的做法: Connection con = DriverManager.getConnection(url, "name", "Password");
如果你装载的驱动程序识别了提供给 DriverManager.getConnection 的 JDBC URL ,那个驱动程序将根据 JDBC URL 建立一个到指定 DBMS 的连接。正如名称所示,DriverManager 类在幕后为你管理建立连接的所有细节。除非你是正在写驱动程序,你可能无需使用此类的其它任何方法,一般程序员需要在此类中直接使用的唯一方法是 DriverManager.getConnection。
DriverManager.getConnection 方法返回一个打开的连接,你可以使用此连接创建 JDBC statements 并发送 SQL 语句到数据库。在前面的例子里,conn 对象是一个打开的连接,并且我们要在以后的例子里使用它。
rs.next(); -- 从查询出来的集合中拿出了一条数据:表示的集合表中的第一个对象。
rs.getInt(int index); 通过索引来获得查询结果集中的某一列的值
rs.getInt(String columName); 通过列名来获得查询结果集中的某一列的值
rs.getInt(1)//等价于rs.getInt("id");
rs.getString(2)//等价于rs.getInt("name");
例子:
String sql = "select * from people p where p.id = ? and p.name = ?";
preparedstatement ps = connection.preparestatement(sql);
ps.setint(1,id);
ps.setstring(2,name);
resultset rs = ps.executequery();