Spring Framework主要包括几个模块:
- 支持IoC和AOP的容器;
- 支持JDBC和ORM的数据访问模块;
- 支持声明式事务的模块;
- 支持基于Servlet的MVC开发;
- 支持基于Reactive的Web开发;
- 以及集成JMS、JavaMail、JMX、缓存等其他模块。
Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的容器(框架)!
Ioc
控制反转:IOC——Inversion of Control,指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们自己在代码中new创建。而使用 Spring 之后。对象的创建都是由给了 Spring 框架。
通常new一个实例,控制权由程序员控制,而”控制反转”是指new实例工作不由程序员来做而是交给Spring容器来做
IoC又称为依赖注入(DI:Dependency Injection)
通过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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="edu.cqupt.poio.Hello">
<!--给对象中的属性设置一个值-->
<property name="str" value="Spring"/>
</bean>
<bean id="dataSource" class="HikariDataSource" />
// 把id为dataSource的组件通过属性dataSource注入到下面组件中
<bean id="bookService" class="BookService">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
总结: 在配置文件加载的时候,Spring容器中管理的对象就已经被初始化了。一旦容器初始化完毕,我们就直接从容器中获取Bean使用它们。
使用注解装配Bean
XML的写法非常繁琐,我们可以使用Annotation配置,可以完全不需要XML,让Spring自动扫描Bean并组装它们,实现自动装配
- @Component
- @Configuration
- @Autowired
- @ComponentScan
- @Bean
- @Qualifier
- @Order
// UserService
@Component
public class UserService {
@Autowired
MailService mailService;
...
}
// AppConfig
@Configuration
@ComponentScan
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
User user = userService.login("bob@example.com", "password");
System.out.println(user.getName());
}
}
保证:
AOP技术看上去比较神秘,但实际上,它本质就是一个动态代理,让我们把一些常用功能如权限检查、日志、事务等,从每个业务方法中剥离出来。
静态代理
动态代理
- 动态代理的代理类是动态生成的,不是我们直接写好的,动态生成代理类
利用反射
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 等会我们用这个类,自动生成代理类
public class ProxyInVocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy(){// 生成得到代理类
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
// 动态代理的本质,就是使用反射机制实现
// 处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target,args);
return result;
}
// 给代理添加功能
public void log(String msg){
System.out.println("[Debug]:执行了" + msg + "方法。");
}
}
Spring的AOP实现就是基于JVM的动态代理。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
Aop 在 不改变原有代码的情况下 , 去增加新的功能。
- Before
- Around
After
@Aspect
@Component
public class LoggingAspect {
// 在执行UserService的每个方法前执行:
@Before("execution(public * com.itranswarp.learnjava.service.UserService.*(..))")
public void doAccessCheck() {
System.err.println("[Before] do access check...");
}
// 在执行MailService的每个方法前后执行:
@Around("execution(public * com.itranswarp.learnjava.service.MailService.*(..))")
public Object doLogging(ProceedingJoinPoint pjp) throws Throwable {
System.err.println("[Around] start " + pjp.getSignature());
Object retVal = pjp.proceed();
System.err.println("[Around] done " + pjp.getSignature());
return retVal;
}
}
我们使用AOP非常简单,一共需要三步:
- 定义执行方法,并在方法上通过AspectJ的注解告诉Spring应该在何处调用此方法;
- 标记@Component和@Aspect;
- 在@Configuration类上标注@EnableAspectJAutoProxy。
使用注解装配AOP
Mybatis-Spring
- 编写数据源配置
- sqlSessionFactory
- sqlSessionTemplate
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--DataSource: 使用Spring的数据源替换mybatis的配置 c3p0 dbcp druid
我们使用Spring提供的jdbc-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--绑定Mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:edu/cqupt/mapper/*.xml"/>
</bean>
<!--SqlSessionTemplate 就是我们使用的的SqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入SqlSessionFactory 因为他没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
或者,使用 sqlSessionFactory
<bean id="userMapper" class="edu.cqupt.mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
// 1 继承 SqlSessionDaoSupport
// 2 使用getSqlSession()方法获得SqlSession
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
public List<User> selectUser() {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.selectUser();
}
}