1.Spring Bean的装配和注入。
1.1 使用XML的方式创建Spring 上下文的方式实现bean的创建及注入。
1. 显式的使用<bean> 标签,直接通过Class属性,设置需要注入bean的全限定名,可以将bean注入到Spring容器中。可以(可选)对对应的bean设置Id或者Neme,如果不设置id或name,将会自动创建默认的全限定名为Name的bean。例如注入了com.citrus.demo.UserService,将就可以通过applicationContext.getBean("com.citrus.demo.UserService")获取到bean。
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<bean name="userService" class="com.citrus.demo.service.UserServiceImpl">
</bean>
<bean name="userController" class="com.citrus.demo.controller.UserController">
<constructor-arg name="userService" ref="userService"/>
</bean>
</beans>
2.使用注解的方式。
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<bean name="userService" class="com.citrus.demo.service.UserServiceImpl">
</bean>
<bean class="com.citrus.demo.controller.UserController">
<constructor-arg name="userService" ref="userService"/>
</bean>
<context:component-scan base-package="com.citrus.demo"/>
<aop:aspectj-autoproxy/>
<context:annotation-config/>
</beans>
2.1 需要指定对应的包扫描路劲 <context:component-scan base-package="com.xx.xx"/>,Spring就会去扫描到指定的带有例如RestController、Component、Service……等注解的类,然后创建指定的Bean。
@RestController
public class UserController {
private final IUserService userService;
@Autowired
public UserController(IUserService userService) {
this.userService = userService;
}
public String findUserOne(){
return userService.findUserOne("admin","123");
}
}
2.2 通过@Configuration注解配合@Bean注解实现注入。@Configuration等效于XML下的 <beans>标签,@Bean等效于<bean>,同样可以Bean的注入。
@Configuration
@ComponentScan("com.citrus.demo")
public class JdbcTemplateConfig {
private final HikariDataSource hikariDataSource;
@Autowired
public JdbcTemplateConfig(HikariDataSource hikariDataSource) {
this.hikariDataSource = hikariDataSource;
}
@Bean
public JdbcTemplate configJdbc() {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(hikariDataSource);
return jdbcTemplate;
}
}
2.Spring Aop技术的使用与AspectJ原生的差异。
1.使用原生的AspectJ实现Aop技术
可以实现完整强大的Aop技术,使用略嫌麻烦,需要借助三方脚本,接触插件进行编译织入,也可以实现运行时织入,需要如下依赖包,在aspectj官网可以看到对应的教程。
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
2.使用Spring的Aop
只需要 导入AspectJWear依赖和Spring-aop依赖支持即可。
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
2.1 使用XML配置的方式使Aop生效。使用<aop: config>……等标签实现,可以实现前置通知、后置通知,环绕通知、抛出异常通知……等。
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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<bean name="userService" class="com.citrus.demo.service.UserServiceImpl">
</bean>
<bean class="com.citrus.demo.controller.UserController">
<constructor-arg name="userService" ref="userService"/>
</bean>
<context:component-scan base-package="com.citrus.demo"/>
<bean name="aspectDemo" class="com.citrus.demo.advice.AspectDemo"/>
<aop:config>
<aop:aspect ref="aspectDemo">
<aop:around method="around"
pointcut="@annotation(com.citrus.demo.advice.anno.TestAdviceAnnotation))"
/>
<aop:after method="after"
pointcut="execution(* com.citrus.demo.service.*.*(..))"
/>
<aop:before method="before"
pointcut="execution(* com.citrus.demo.service.*.*(..))"
/>
</aop:aspect>
</aop:config>
<context:annotation-config/>
</beans>
增强类:
@Aspect
public class AspectDemo {
public void before() {
System.out.println("前置通知执行!!!");
}
public void after() {
System.out.println("后置通知执行!!!");
}
public String around(ProceedingJoinPoint joinPoint) {
String result = "";
System.out.println("环绕通知 执行!!");
try {
Object[] args = joinPoint.getArgs();
for (Object o : args) {
System.out.println("参数有:" + (String) o);
}
result = (String) joinPoint.proceed();
System.out.println("返回值是" + result);
} catch (Throwable e) {
e.printStackTrace();
result = "发生未知的错误: " + e.getMessage();
}
return result;
}
}
2.2 使注解的方式使Aop生效。注解是同@Aspect和Component注解,并在Spring ApplicationContext上下文中配置使用<aop:aspectj-autoproxy/>开启自动扫描Aspect类即可。还需要开启组件扫描<context:component-scan base-package="com.citrus.demo"/>
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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<bean name="userService" class="com.citrus.demo.service.UserServiceImpl">
</bean>
<bean class="com.citrus.demo.controller.UserController">
<constructor-arg name="userService" ref="userService"/>
</bean>
<context:component-scan base-package="com.citrus.demo"/>
<bean name="aspectDemo" class="com.citrus.demo.advice.AspectDemo"/>
<aop:aspectj-autoproxy/>
<context:annotation-config/>
</beans>
Aspect类:
@Aspect
@Component
public class AspectDemo {
@Before(value = "execution(* com.citrus.demo.service.*.*(..))")
public void before() {
System.out.println("前置通知执行!!!");
}
@After(value = "@annotation(com.citrus.demo.advice.anno.TestAdviceAnnotation)")
public void after() {
System.out.println("后置通知执行!!!");
}
@Around(value = "@annotation(com.citrus.demo.advice.anno.TestAdviceAnnotation)")
public String around(ProceedingJoinPoint joinPoint) {
String result = "";
System.out.println("环绕通知 执行!!");
try {
Object[] args = joinPoint.getArgs();
for (Object o : args) {
System.out.println("参数有:" + (String) o);
}
result = (String) joinPoint.proceed();
System.out.println("返回值是" + result);
} catch (Throwable e) {
e.printStackTrace();
result = "发生未知的错误: " + e.getMessage();
}
return result;
}
}
其中Around环绕通知是常用的增强手段,它提供了强大的方法增强的支持。可以通过ProceedingJoinPoint 对增强的方法实现丰富的操作,可以通过joinPoint.getArgs()拿到增强方法的形参及其传递的参数,其中Around通知返回的参数,就是原方法的返回值,需要使用joinPoint.proceed()执行原方法后得到返回值显式的返回。包含对于方法执行的异常处理,Catch Throwable的顶层异常,对于异常可以进行统一的处理,方便维护管理。
对于Aop在开发中可以极大的提高代码的可维护性,可以实现一些十分强大的功能,常用的有:使用Aop实现日志的记录打印,为一些接口增加缓存,拦截认证等……可以极大地简化一些公共重复的代码的工作,使一些公共的行为可以进行统一的管理,例如200个接口需要记录日志,直接在接口上添加,效率很低,降低代码阅读性,后期难以维护,需要升级的时候需要手动更改每一个接口的代码。使用Aop以后,通过PointCut指定的表达式,可以对某一类方法实现增强,对标有某个注解的方法实现增强,对于某个包路径下的方法实现增强。后期维护只需要更改增强方法即可,极大提升了维护能力。
3.Spring 事务控制。
1.在Servlet中需要进行事务控制。
使用session.setAutoCommmit(false),session.commit,session.rollback可以简单的对jdbc事务进行控制,需要显式的在方法末尾进行commit操作,需要显式的在catch exception中对事务进行回滚。
@Override
public List<ServiceCategory> findCategoryList() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<ServiceCategory> serviceCategories = new ArrayList<>();
try {
connection = HikariCpUtils.getHikariConnection();
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement("select * from service_category");
resultSet = preparedStatement.executeQuery();
ServiceCategory serviceCategory = null;
while (resultSet.next()) {
serviceCategory = new ServiceCategory();
serviceCategory.setId(resultSet.getLong(1));
serviceCategory.setName(resultSet.getString(2));
serviceCategory.setInfo(resultSet.getString(3));
serviceCategory.setLink(resultSet.getString(4));
serviceCategory.setState(resultSet.getInt(5));
serviceCategory.setCreateUser(resultSet.getString(6));
serviceCategory.setModifiedUser(resultSet.getString(7));
serviceCategory.setCreateTime(resultSet.getTimestamp(8).toLocalDateTime());
serviceCategory.setModifiedTime(resultSet.getTimestamp(9).toLocalDateTime());
serviceCategories.add(serviceCategory);
}
} catch (SQLException e) {
try {
if (connection != null) {
connection.rollback();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
try {
if (connection != null) {
connection.commit();
}
} catch (SQLException e) {
e.printStackTrace();
}
HikariCpUtils.closeConnection(connection, preparedStatement, resultSet);
}
return serviceCategories;
}
在spring中,提供了对于事务的支持与管理。PlatformTransactionManager 接口是 spring 的事务管理器,提供了常用的操作事务的方法……未完待续