<bean id="myId" class="MyClass">bean>
// 初始化容器 ApplicationContext context = new
ClassPathXmlApplicationContext("application-context.xml");
// 获取对象
MyClass my = context.getBean("myId", MyClass.class);
Bean 的作用域有 singleton, prototype, request, session, global session, application. 其中后四种是在web应用中使用的。
singleton: bean 的默认作用域, 也可通过
来显式地指定作用域。 保证只会有一个实例存在(后续创建的实例与第一个创建的实例指向同一个对象)_
prototype: 每次引用该bean时都会创建一个新的实例。
创建 在添加Bean时指定初始化方法的名称,并在类中实现该方法即可
<bean id="myId" class="MyClass" init-method="init">bean>
public class MyClass {
public void init() {}
}
销毁 在添加Bean时指定销毁方法的名称,并在类中实现该方法即可
<bean id="myId" class="MyClass" init-method="cleanup">bean>
public class MyClass {
public void cleanup() {}
}
注意: scope为singleton的bean的destroy方法则是在容器关闭时执行,而scope为prototype的bean是不会执行destroy方法的
public class MyClass {
Dependency dp = null;
public MyClass (Dependency instanceOfSubClassOfDependency) {
dp = instanceOfSubDependency;
}
}
public class MyClass {
Dependency dp = null;
public void setDp(Dependency instanceOfSubClassOfDependency) {
dp = instanceOfSubClassOfDependency;
}
}
如果是强依赖,最好选择构造函数注入,如果是可选依赖,最好 选择 Setter 方法注入
<bean id="myId" class="MyClass">
<constructor-arg value = "...">constructor-arg>
<constructor-arg index = "0" value = "...">constructor-arg>
<constructor-arg type = "java.lang.String" value = "...">constructor-arg>
<constructor-arg name = "argName" value = "...">constructor-arg>
bean>
public class MyClass {
String arg0;
int arg1;
public MyClass (Map paras) {
this.arg0 = paras.get("arg0");
this.arg1 = Integer.valueOf(paras.get("arg1"));
}
}
<bean id="myId" class="MyClass">
<constructor-arg>
<map>
<entry key = "arg0" value = "value0">entry>
<entry key = "arg1" value = "value1">entry>
map>
constructor-arg>
bean>
<bean id="myClassProperties" class =
"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:myClass.properties"/> bean>
<bean id="myId" class="MyClass">
<constructor-arg name = "arg0" value = "${arg0}">constructor-arg>
<constructor-arg name = "arg1" value = "${arg1}">constructor-arg>
bean>
<bean id="myId2" class="MyClass2">
<constructor-arg>
<ref bean="myId"/>
constructor-arg>
bean>
<bean id="myId" class="MyClass">
<constructor-arg name = "arg0" value = "${arg0}">constructor-arg>
<constructor-arg name = "arg1" value = "${arg1}">constructor-arg>
bean>
public class MyClass {
private String arg0;
private int arg1;
public void setArg0(String arg0) {
this.arg0 = arg0;
}
public void setArg1(int arg1) {
this.arg1 = arg1;
}
}
<bean id="myId" class="MyClass">
<property name="arg0" value="value0">property>
<property name="arg1" value="value1">property>
bean>
如果一个bean的依赖很多,或者需要添加依赖,手动修改配置文件会很低效。所以Spring提供了自动装配(Autowiring)的机制 自动装配有几种类型:
注意: Autowire是根据 setter 进行自动注入的,所以需要实现 setter方法
xml
XML文件配置Bean与Annotation的比较:
* XML: 繁琐,代码独立
* Annotation: 简洁,代码耦合
几种Annotation:
1. @Component
: 定义Bean
2. @Value
: properties 注入
3. @Autowired
& @Resource
: 自动装配依赖
4. @PostConstruct
& @PreDestroy
: 生命周期回调
要使用Annotation 需要在 XML配置文件中添加
@Component("myId")
// 如果不指定id的话,默认为MyClass
public class MyClass {
@Value("value0") String para0;
@Value("value1") int para1;
}
使用时需要添加aspectj依赖 在spring的配置文件中也需要在beans的namespace中添加aop的tag
<beans xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy />
<bean id = "loggingAspect" class = "package.LoggingAspect"> bean>
beans>
// LoggingAspect.java
import org.aspectj.lang.annotation.Aspect;
// Aspect 的实现类需要添加 @Aspect的Annotation
@Aspect
public class LoggingAspect {
// 定义Pointcut
// Pointcut 表达式: designator(modifiers? return-type declaring-type? name(param) throws?) // 1.modifiers 是可选的,表示匹配的函数的修饰符,如public、private等 // 2.declaring-type 是可选的,表示匹配函数所在的包名,类名
// 例1. 匹配所有的public函数
// @Pointcut("execution(public * *(..))")
// private void publicMethod() {}
// 例2. 所有以save开头的函数
// @Pointcut("execution(* save*(..))")
// private void saveMethod() {}
// 例3. 通过组合已有的Pointcut来实现匹配所有以save开头的public函数
// @Pointcut("execution(publicMethod() && saveMethod())")
// private void publicSaveMethod() {}
@Pointcut("execution(* package.ObjectClass.*(..))")
private void pointcutName() {}
// 定义Advice
@Before("package.LoggingAspect.pointcutName()") // 此处也可以直接用pointcut表达式代替而不是填写pointcut名称
public void beforeActionName() {}
// 其他Advice的annotation
// @AfterReturing
// @AfterThrowing
// @After 等等
// 通过JoinPoint 获取函数上下文信息
@Before("pointcutName()")
public void afterActionName(JoinPoint jp) {
System.out.println(jp.getSignature());
}
// 注意@Around与其他有所不同,需要通过ProceedingJoinPoint获取上下文信息
@Around("pointcutName()")
public void aroundActionName(ProceedingJoinPoint pjp) {
System.out.println("Start"); // 调用目标函数执行 pjp.proceed();
System.out.println("Done");
}
// 获取返回值
@AfterReturing(pointcut="pointcutName()", returning="retVal")
public void afterReturingActionName(Object retVal) {
// do something with return value
}
}
<aop:config>
<aop:aspect id="loggingAspect" ref="loggingBean">
<aop:pointcut id="pointcutName" expression="...">
<aop:before pointcut-ref="pointcutName" method="methodInLoggingAspect">aop:before>
aop:pointcut>
aop:aspect>
aop:config>
<bean id="loggingBean" class="package.LoggingAspect">
bean>
<bean id="JdbcExampleDao" class="package.JdbcExmapleDao">
<property name="dataSource" ref="dataSource"/>
bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.dirverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<context:property-placeholder location="db.properties"/>
jdbc.dirverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost/database
jdbc.username = username
jdbc.password = password
@Repository
public class JdbcExampleDao {
private JdbcTemplate jdbcTemplate;
@Resource
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
}
// org.springframwork.transaction
// spring 提供的事务接口
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
<beans xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.dirverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<context:property-placeholder location="db.properties"/>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="daoOperation" expression="execution(Pointcut表达式)"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="daoOperation"/>
aop:config>
beans>
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.dirverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<context:property-placeholder location="db.properties"/>
@Transactionnal(propagation = Propogation.REQUIRED, rollbackFor = Exception.class)
public void doSomething() {
// do work
}
@Transactional 的配置属性
// 定义TransactionTemplate
public class Service {
private final TransactionTemplate transactionTemplate;
public Service(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
this.transactionTemplate.setIsolationLevel(...);
this.transactionTemplate.setTimeout(...);
...
}
// 使用TransactionTemplate
public Object someMethod() {
return transactionTemplete.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
// doSomething
// return something
}
});
}
}
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("transactionName");
def.setPropagationBehavior(...);
TransactionStatus status = txManager.getTransaction(def);
try {
// do some trasaction logic
} catch (Exception e) {
txManager.roolback(status);
throw ex;
}
txManager.commit(status);
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
bean>
public interface UserMapper {
User getUser(String userId);
}
<mapper namespace="package.UserMapper">
<select id = "getUser" resultType = "User">
select * from users where id = #{userId}
select>
mapper>
也可以用 Annotation 定义 Mapper
public interface UserMapper {
@Select("select * from users where id = #{userId}")
User getUser(@Param("userId") String userId);
}
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="package.UserMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
也可通过Annotation配置
<mybatis:scan base-package="package"/>
public class SomeService {
@Resource
private UserMapper userMapper;
public User getUser(String userId) {
return userMapper.getUser(userId);
}
}
通过 SqlSessionTemplate 可以使用 MyBatis 中 session 的接口
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
bean>
public class UserDAO {
@Resource
private SqlSession sqlSession;
public User getUser(String userId) {
return (User) sqlSession.selectOne("package.UserMapper.getUser", userId);
}
}
为什么要使用 Spring Web 框架?
以 Servlet
为核心构建的, 其核心是 DispatherServlet
, 在其背后提供了一些工具来解决上述的问题。
Handler Mapping
用于解决请求路径到处理逻辑的映射关系Controller
用于负责视图和模型之间的关系View Resolver
和 View
则是视图相关的工具在 web.xml
文件中进行配置
<servlet>
<servlet-name>exampleservlet-name>
<servlet-class>org.springframework.web.servlet.DispatherServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>exampleservlet-name>
<url-pattern>/api/*url-pattern>
servlet-mapping>
同时在 WEB-INF
目录下配置一个名为 [servlet-name]-servlet.xml
的配置文件用于配置DispatherServlet
可配置项:
注意: DispatherServlet 不是唯一的,可以定义多个 DispatherServlet
可以通过 ContextLoaderListener
来配置多个 DispatherServlet 之间共同的配置
首先需要在 web.xml
文件中进行配置
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>/WEB-INF/applicationContext*.xmlparam-value>
context-param>
// 需要在spring配置文件中开启自动发现才能使用Annotation来定义Controller
//
@Controller
@RequestMapping(value = "/hello")
public class HelloController {
// 当访问地址为 /hello/spring 时就会将请求转接到spring函数的处理中,输出"Hello, Spring Web"
@RequestMapping(value = "/spring")
public void spring(HttpServletResponse response) throws IOException {
response.getWriter().write("Hello, Spring Web!!");
}
}
RequestMapping 的属性
value & path : 路径, 比如 “/hello”
注意:
以下代码效果完全相同
@RequestMapping("/hello")
@RequestMapping(value = "/hello")
@RequestMapping(path = "/hello")
示例:
// RestAPI 的路径参数匹配
@RequestMapping(path="users/{userId}")
public String webMethod(@PathVariable String userId) {
// do Work
}
函数参数:
函数返回值:
@RequestMapping(value = "/spring/{user}")
public void spring(
@PathVariable("user") String user,
@RequestParam("msg") String msg,
@RequestHeader("host") String host,
HttpServletRequest request,
Writer writer) throws IOException {
writer.write("URI: " + request.getRequestURI());
writer.write("Hello, " + user + ": " + msg + ", host=" + host);
}
@RequestMapping(value = "/spring/login")
public void login(
@RequestParam("name") String name,
@RequestParam("password") String password,
Writer writer)
throws IOException {
// do work
}
对于有很多信息的表单,挨个写 RequestParam 就会显得繁琐, Spring 提供了一个 ModelAttribute 的 Annotation
可以从参数匹配一个model
@RequestMapping(value = "/spring/login")
public void login(@ModelAttribute User user, Writer writer) {
// do work
}
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000"/>
bean>
@RequestMapping(path = "/form", method = RequestMethod.POST)
public String handleFormUpload(@RequestParam("file") MultipartFile file) {
// do work
}
@RequestMapping("/something")
public ResponseEntity handle(HttpEntity<byte[]> requestEntity) {
String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader");
byte[] requestBody = requestEntity.getBody();
// do something with request header and body
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity("Hello World", responseHeaders, HttpStatus.CREATED);
}
@RequestMapping(value = "/spring")
@ResponseBody
public String spring(@RequestBody String body) throws IOException {
return "Hello" + body;
}
InternalResourceViewResolver
一般处理 Servlet, JSP
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<proerty name="prefix" value="/WEB-INF/jsp/"/>
<proerty name="suffix" value=".jsp"/>
bean>
如果请求处理函数返回的view名称为 resultView
, 则View的路径为 /WEB-INF/jsp/resultView.jsp
FreeMarkerViewResolver
针对 Freemarker
模板引擎的 viewResolver
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<proerty name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<proerty name="cache" value="true"/>
<proerty name="prefix" value=""/>
<proerty name="suffix" value=".ftl"/>
bean>
ContentNegotiatingViewResolver
是 ViewResolver 的组合,可以根据客户端的请求返回不同的view
user.json
, user.xml
, user.pdf
Accept
头来决定: 如 application/json
, application/xml
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="viewResolvers">
<list>
<bean id="viewResolver" class="org.springframwork.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
bean>
list>
property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
list>
property>
bean>
Freemarker 指令
<#directivename parameters>
#directivename parameters>
if 指令:
<#if balance < 10> poor guy
<#elseif balance = 10> not so poor
<#else> haha
#if>
list 指令: freemarker 的 foreach
<#list animals as animal>
${animal.name}<br>
#list>
include 指令:
将需要重复使用的固定内容插入
<#include "/copyright_footer.html">