配置的三种写法:XML-based configuration 基于 XML 文件,Annotation-based configuration 基于 Annotation ,以及 Java-based configuration 基于 Java 代码配置。
DI 注解(Autowired)
需要配置 DI 注解解析器,Spring3.0之前,需要手动配置 Autowired 注解的解析程序,Web开发中必须配置。<context:annotation-config/>
Autowired 注解和 Resource 注解
Autowired 注解和 Resource 注解都可以完成相同功能的操作,Autowired 是 Spring 提高,Resource 是 JavaEE 提供。(spring-context 包下)
相同点:
- 自动的把属性需要的对象找出来,自动注入
- 贴在字段或者 setter 方法上面,一般贴在字段上,贴字段上不需要使用set方法。
可以注入一些 Spring 内置的重要对象,甚至是 Servlet 的API,比如:BeanFactory、ApplicationContext、ServletContext等
不同点:
Autowired 和 Resource 注解都必须要能找到对应的对象,否则报错。Autowired 注解可以通过 required=false 来避免这个问题(required=false)
Autowired 按照类型找,找不到按名字找,可以配合 @qualifier限定 注解使用,表示直接查找这个名字的对象
| 12
 3
 4
 5
 
 | public class Somebean {@Autowired
 @Qualifier("otherbean")
 private Otherbean other;
 }
 
 | 
Reource 按名字找,找不到按类型找。
| 12
 3
 4
 
 | public class Somebean {@Resource(name = "otherbean")
 private Otherbean other;
 }
 
 | 
原来的方式:
| 12
 3
 4
 5
 
 | <context:annotation-config/><bean id="otherbean" class="cn.lizhaoloveit.annotation.Otherbean"/>
 <bean id="somebean" class="cn.lizhaoloveit.annotation.Somebean">
 <property name="other" ref="otherbean"></property>
 </bean>
 
 | 
现在的方式:
| 12
 
 | <bean id="otherbean" class="cn.lizhaoloveit.annotation.Otherbean"/><bean id="somebean" class="cn.lizhaoloveit.annotation.Somebean"/>
 
 | 
需求
把 OtherBean 对象设置给 SomeBean 对象的 other 属性。
Value注解
Autoweired 和 Resource 注解用于注入对象,Value注解用于注入常量数据。
server.properties 文件
| 12
 
 | server.port=8888server.path=/
 
 | 
Java 代码:
| 12
 
 | @Value("${server.port}")private int port;
 
 | 
引入配置文件
| 1
 | <context:property-placeholder location="classpath:db.properties,classpath:server.properties"/>
 | 
或者
| 12
 
 | <context:property-placeholder location="classpath:db.properties" ignore-unresolvable="true"/><context:property-placeholder location="classpath:server.properties" ignore-unresolvable="true"/>
 
 | 
IoC 注解(bean)
在xml文件配置了<context:component-scan>标签后,spring容器可以自动去扫描base-pack所指定的包或其子包下面的java类文件,如果扫描到有@Component、@Controller、@Service 、@Repository等注解修饰的Java类,则将这些类注册为spring容器中的bean。
IoC 的注解解释器配置
| 12
 3
 4
 
 | <context:annotation-config/>
 
 <context:component-scan base-package="cn.lizhaoloveit.ioc"/>
 
 | 
- @Repository用于标注数据访问组件,即 DAO 组件。
- @Service用于标注业务层组件,即 Service 组件
- @Controller只用于标注控制层组件(Spring MVC 的 Controller)
- @Component泛指组件,当组件不好归类的时候,可以使用跟这个注解。
默认 id 是把被标注类名的首字母小写后的类名。
需要配置 IoC 注解的解析器:
context:component-scan base-package=""表示去哪个包中及其子包中扫描组件注解
代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration
 public class App
 {
 @Autowired
 private Somebean somebean;
 @Test
 public void testName() throws Exception {
 System.out.println(somebean);
 }
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | @ToString@Component
 public class Somebean {
 @Autowired
 @Qualifier("other")
 private Otherbean other;
 }
 
 @Component("other")
 public class Otherbean {
 }
 
 | 
最后输出:Somebean(other=cn.lizhaoloveit.ioc.Otherbean@1d76aeea)
原理如下:
在类型上贴注解 @Componenet("other") 相当在配置文件中加入如下配置
<bean id="other" class="全限定名"
在字段上贴注解,@Autowired,默认会先找 Otherbean 类型的值注入,如果找不到会找 otherbean id 名字的值注入,如果都没有会报错。如果加入注解 @Qulifier("other"),表示会加载指定 id为 other 的bean 对象注入。
作用域注解(scope)
| 12
 3
 4
 
 | @Component("other")@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
 public class Otherbean {
 }
 
 | 
相当于:<bean id="other" class="...Otherbean" scope="singleton"/>
初始化和销毁注解
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | @Component("other")@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
 public class Otherbean {
 @PostConstruct
 public void open() {
 System.out.println("初始化方法");
 }
 @PreDestroy
 public void close() {
 System.out.println("关闭");
 }
 }
 
 | 
| 12
 3
 
 | <bean id="other" class="...Otherbean" scope="singleton"init-method="open" destro-method="close"
 />
 
 | 
AOP注解
AOP的注解解释器:
| 12
 3
 4
 5
 6
 
 | <context:annotation-config/>
 
 <context:component-scan base-package="cn.lizhaoloveit.ioc"/>
 
 <aop:aspectj-autoproxy/>
 
 | 
以前基于 xml 的做法:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | <import resource="classpath:applicationContext.xml" />
 
 <context:annotation-config/>
 
 <context:component-scan base-package="cn.lizhaoloveit.aopjdkproxy"/>
 
 <aop:aspectj-autoproxy proxy-target-class="false"/>
 
 
 <bean id="txManager" class="cn.lizhaoloveit.aopjdkproxy.TransactionManager"/>
 
 <aop:config proxy-target-class="false">
 <aop:aspect ref="transactionManager">
 <aop:pointcut expression="execution(* cn.lizhaoloveit.aop.service.*Service.*(..))"
 id="txPointcut"/>
 <aop:before method="begin" pointcut-ref="txPointcut"/>
 <aop:after-returning method="commit" pointcut-ref="txPointcut"/>
 <aop:after-throwing method="rollback" pointcut-ref="txPointcut" throwing="exception"/>
 <aop:after method="close" pointcut-ref="txPointcut"/>
 <aop:around method="around" pointcut-ref="txPointcut"/>
 </aop:aspect>
 </aop:config>
 
 | 
<aop:aspect> 标签的作用是关联项目中的增强模块,这时只需要在增强类上贴上注解即可。@Aspect 默认是按类型查找。
| 12
 3
 
 | @Aspect@Component
 public class TransactionManager
 
 | 
<aop:pointcut expression="execution(* cn.lizhaoloveit.aop.service.*Service.*(..))"          id="txPointcut"/> 标签的作用是找到业务流的切入点,我们可以直接在增强模块类(TransactionManager)中使用注解来表示
| 12
 3
 4
 
 | @Pointcut("execution(* cn.lizhaoloveit.aop.service.*Service.*(..))")public void txPointcut() {
 
 }
 
 | 
上面的代码表示的含义是,拦截 execution 中的所有方法调用,并且给该 execution 设置一个 id值为 方法名 txPointcut。
最后只要规定切入点的位置和增强方法即可:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 
 | @Aspect@Component
 public class TransactionManager {
 @Pointcut("execution(* cn.lizhaoloveit.aop.service.*Service.*(..))")
 public void txPointcut() {
 }
 @Before("txPointcut()")
 public void begin(JoinPoint jp) {
 System.out.println("事务开始...");
 }
 @AfterReturning("txPointcut()")
 public void commit(JoinPoint jp) {
 System.out.println("当前连接点签名 :" + jp.getSignature());
 System.out.println("提交事务...");
 }
 @AfterThrowing("txPointcut()")
 public void rollback(JoinPoint jp, Throwable exception) {
 System.out.println("当前连接点签名 :" + jp.getSignature());
 System.out.println("回滚..." + exception.getMessage());
 }
 @After("txPointcut()")
 public void close() {
 System.out.println("关闭资源...");
 }
 @Around("txPointcut()")
 public Object around(ProceedingJoinPoint pjp) {
 Object res = null;
 begin(pjp);
 try {
 System.out.println("执行目标方法");
 
 res = pjp.proceed();
 commit(pjp);
 } catch (Throwable e) {
 e.printStackTrace();
 rollback(pjp, e);
 } finally {
 close();
 }
 return res;
 }
 }
 
 | 
ProxyApp-context.xml
| 12
 3
 4
 
 | <import resource="classpath:applicationContext.xml" />
 <context:component-scan base-package="cn.lizhaoloveit.aopjdkproxy"/>
 <aop:aspectj-autoproxy proxy-target-class="false"/>
 
 | 
总结:xml 配置文件,通过 IoC 注解解析器告诉 Spring 容器去扫描 base-package 包下的 java 类文件,<aop:aspctj-autoproxy> 配置 aop 注解解释器,扫描时,发现了 TransactionManager,带有 @Aspect,并且扫描到 @Component,就会创建 Transaction对象,并且将其作为切面模块,插入哪个业务流程呢?由 @Pointcut 告诉动态代理对象去拦截哪些方法,去在合适的时机执行增强方法。
Tx注解
一般用于 list、get、query 开头的 Service 方法使用 事务的 read-only 模式。
Transactional 注解
具体使用:
| 12
 3
 4
 
 | <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"<property name="dataSource" ref="dataSource"/>
 </bean>
 <tx:annotation-driven transaction-manager="txManager" />
 
 | 
Transactional 贴在业务类上,也可以贴在业务类方法之上:
- 贴在类上:表示该类中所有的方法都使用 Transactional 注解的属性配置
- 贴在方法上:只针对被贴的这一个方法,一般用于做单独配置
一般的,我们可以在业务类上直接贴该注解,并在查询方法上设置 readOnly 属性为 true,一定要开启 Tx 注解的解释器
配置 JDBC 事务管理器,使用 CGLIB
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"<property name="dataSource" ref="dataSource"/>
 </bean>
 
 <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
 init-method="init" destroy-method="close">
 <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>
 
 <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | @Service@Transactional
 public class AccountServiceImpl implements IAccountService {
 @Autowired
 private IAccountDAO dao;
 public void trans(Long outId, Long inId, int money) {
 dao.transOut(outId, money);
 int a = 1 / 0;
 dao.transIn(inId, money);
 }
 }
 
 | 
SpringMVC 注解(Controller、RequestMapping)
一个简单的基于注解开发的 SpringMVC,
- 需要在 web.xml 中设置一个调度器 dispatcherServlet。
web.xml
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | <servlet>
 <servlet-name>SpringMVC</servlet-name>
 
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 
 
 
 
 
 
 
 <init-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:mvc2.xml</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
 <servlet-name>SpringMVC</servlet-name>
 <url-pattern>/</url-pattern>
 </servlet-mapping>
 
 | 
| 12
 3
 4
 
 | <context:component-scan base-package="cn.lizhaoloveit.hello"/>
 
 <mvc:annotation-driven/>
 
 | 
IoC 注解解释器,会扫描其下面的注解标签,遇到 @Component、@Controller、@Service 、@Repository,会生成对应的 <bean> 实例对象,
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | @Controllerpublic class UserController {
 
 @RequestMapping("/abc")
 public ModelAndView sayHello() {
 System.out.println("...hello...");
 ModelAndView mv = new ModelAndView();
 mv.addObject("username", "will");
 mv.setViewName("WEB-INF/view/hello/hello.jsp");
 return mv;
 }
 }
 
 | 
@RequestMapping(“/abc”),与url做映射,处理器中可以写多个。
问题,理论上讲,mvc.xml 需要配置4个东西
- 处理器映射器 BeanNameUrlHandlerMapping
- 处理器适配器 SimpleControllerHandlerAdapter
- 视图解析器 InternalResourceViewResolver
- 处理器 handler
 为什么使用注解后,我们就创建了 Controller,就可以使用了呢?
因为在 spring-webmvc.jar 包中,有一个 properties 文件,
/org/springframework/web/servlet/DispatcherServlet.properties,

Mybatis-Spring 注解
创建 Mapper 代理对象,以前的做法:
| 12
 3
 4
 5
 6
 
 | <bean id="userMapper"class="org.mybatis.spring.mapper.MapperFactoryBean">
 <property name="sqlSessionFactory" ref="mySqlSession" />
 <property name="mapperInterface"
 value="cn.lizhaoloveit.ssm.mapper.UserMapper" />
 </bean>
 
 | 
使用注解后的做法:
| 12
 3
 4
 
 | <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
 <property name="basePackage" value="cn.lizhaoloveit.ssm.mapper"></property>
 </bean>
 
 | 
并且可以直接把 SQL 卸载 Mapper 接口对应的方法上,不再使用 Mapper 映射文件。
UserMapper.java
| 12
 
 | @Select("select id, name, age from t_user")List<User> selectAll();
 
 | 
总结:
IoC 注解
作用:被贴的类,交给 Spring 管理(会被创建对象,存储在 Spring 容器中)
注解:
- Repository(DAO)
- Service(一般贴 Service 类)
- Controller(只能贴 Controller 类)
- Component(非上述所有类,默认 id 为类名首字母小写)
XML:
| 12
 
 | <bean id="someBean" class="cn.lizhaoloveit.SomeBean" scope="singleton" init-method="open" destroy-method="close">
 
 | 
解析器:<context:component-scan basePackage="cn.lizhaoloveit.ssm">
使用注解操作如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | @Component("someBean")@Scope("singleton")
 public class SomeBean {
 @PostConstruct
 public void open() {
 }
 @PreDestroy
 public void close() {
 }
 }
 
 | 
DI 注解
作用:从容器中找到指定的 bean 对象,并设置给当前被贴标签的字段
注解:Autoweired、Resource    功能一样
XML:
| 12
 3
 4
 
 | <bean id="otherBean" class="...OtherBean"/><bean id="someBean" class="...SomeBean">
 <property name="other" ref="otherBean"/>
 </bean>
 
 | 
使用注解操作如下:
解析器:<context:annotation-config/>
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | @Componentpublic class OtherBean {
 
 }
 @Component
 public class SomeBean {
 @Autowired
 private OtherBean other;
 }
 
 | 
Tx注解
作用:让 Service 组件实现数据库事务管理操作。
注解:@Transactional
创建事务功能类对象
| 12
 3
 
 | <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"<property name="dataSource" ref="dataSource"/>
 </bean>
 
 | 
XML 配置
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"init-method="init" destroy-method="close">
 <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>
 
 
 <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
 
 | 
使用注解操作如下:
解析器:<tx:annotation-driven transaction-manager="txManager"/>
在 Service 实现类上,使用 Transactional 注解
MVC注解
XML
@Controller:声明当前类为控制器,让 Spring 容器创建对象
@RequestMapping: 贴在类和方法上,表示访问当前方法的 url (“/类url + /方法url”)
| 12
 3
 4
 5
 6
 7
 8
 
 | @Controller@RequestMapping("/xxx")
 public class HelloController {
 @RequestMapping("/abc")
 public ModelAndView sayHello() {
 return null;
 }
 }
 
 | 
此时访问:localhost/xxx/abc
AOP注解
| 12
 3
 4
 5
 
 | public class LoginAdvice {public void writeLog() {
 syso("记录日志")
 }
 }
 
 | 
XML
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | 
 <bean id="transactionManager" class="cn.lizhaoloveit.aopjdkproxy.TransactionManager"/>
 
 
 
 
 <aop:config proxy-target-class="false">
 
 
 <aop:aspect ref="transactionManager">
 
 <aop:pointcut expression="execution(* cn.lizhaoloveit.aop.service.*Service.*(..))" id="txPointcut"/>
 <aop:before method="begin" pointcut-ref="txPointcut"/>
 <aop:after-returning method="commit" pointcut-ref="txPointcut"/>
 <aop:after-throwing method="rollback" pointcut-ref="txPointcut" throwing="exception"/>
 </aop:aspect>
 </aop:config>
 
 | 
注解:
- Aspect 贴在增强类之上,表示一个切面 what
- Pointcut 编写切入点表达式 where
- Before 切入时机 when
- …
解析器:
<context:component-scan basePackage="..."> 解析 Component
<aop:aspectj-autoproxy> 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | @Component@Aspect
 public class LoginAdvice {
 @Pointcut("execution(* cn.lizhaoloveit.ssm.*Service.*(..))")
 public void Xxx() {
 }
 @Before("Xxx()")
 public void writeLog() {
 syso("日志记录");
 }
 }
 
 |