Spring
Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
所谓的 IOC,即对象由Spring来创建、管理、装配,IOC 实现方式是依赖注入 DI
Spring默认创建对象,是在创建Spring容器时,会创建配置文件中所有的对象,默认调用有参构造
IOC创建对象
IOC 默认使用 无参构造函数 创建对象,但也可以使用有参构造器:
-
通过下标赋值
<bean id="hello" class="com.wang.pojo.Hello">
<constructor-arg index="0" value="王"/>
</bean>
-
通过类型赋值
<bean id="hello" class="com.wang.pojo.Hello">
<constructor-arg type="java.lang.String" value="王"/>
</bean>
-
通过参数名称赋值
<bean id="hello" class="com.wang.pojo.Hello">
<constructor-arg name="str" value="李"/>
</bean>
配置文件加载时,容器中管理的对象已经初始化了
配置说明
alias
<alias name="hi" alias="sdskdjsnfdjn"/>
bean
// id为对象名,class为全类名,name为别名,可取多个
<bean id="hi" class="com.wang.pojo.Hello" name="hi2 h3,h4;h5">
<property name="str" value="li"/>
</bean>-->
import
// 可将多个配置文件合并为一个
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
DI 依赖注入
-
构造器注入 (见 IOC 创建对象)
-
set方式注入(属性注入)
依赖:bean对象的创建依赖于容器! 注入:bean对象中的所有属性,由容器来注入!
-
拓展方式注入:
p命名空间注入(属性):需要在xml头部添加:xmlns:p="http://www.springframework.org/schema/p",本质为set注入,需要无参构造和set方法
c命名空间注入(构造):需要在xml头部添加:xmlns:p="http://www.springframework.org/schema/c",本质为构造器注入,需要有参构造
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbies;
private Map<String,String> card;
private Set<String> games;
private Properties info;
private String wife;
}
public class Address {
private String address;
}
set 注入:
<bean id="address" class="com.wang.pojo.Address">
<property name="address" value="南京"/>
</bean>
<bean id="student" class="com.wang.pojo.Student">
<property name="name" value="王"/>
<!-- Bean注入,ref -->
<property name="address" ref="address"/>
<!-- 数组注入,array -->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
</array>
</property>
<!-- List注入,list -->
<property name="hobbies">
<list>
<value>听歌</value>
<value>看电影</value>
<value>敲代码</value>
</list>
</property>
<!-- Map注入,map -->
<property name="card">
<map>
<entry key="身份证" value="123456"/>
<entry key="银行卡" value="654321"/>
</map>
</property>
<!-- Set注入,set -->
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
</set>
</property>
<!-- Null注入,null -->
<property name="wife">
<value>null</value>
<!--<null/>-->
</property>
<!-- Properties注入,Properties -->
<property name="info">
<props>
<prop key="学号">123</prop>
<prop key="姓名">张三</prop>
</props>
</property>
</bean>
自动装配
默认单例模式(singleton),还有原型模式(prototype)、request、session、application、webSocket
隐式的自动装配Bean,自动装配是Spring满足bean依赖的一种方式!
byName 会自动在上下文查找,和自己对象set方法后面的值对应的 bean_id,需要保证所有bean的id唯一
byType 会自动在上下文查找,和自己对象属性类型相同的 bean,需要保证所有bean的class唯一
<bean id="cat" class="com.wang.pojo.Cat"/>
<bean id="dog" class="com.wang.pojo.Dog"/>
<bean id="people" class="com.wang.pojo.People" autowire="byName">
<property name="name" value="小王"/>
<!-- <property name="cat" ref="cat"/>-->
<!-- <property name="dog" ref="dog"/>-->
</bean>
注解实现自动装配
在 xml 中添加 context 网址 及 < context:annotation-config /> 开启自动装配,并在实体类 People 中的 Cat 类和 Dog 类加上注解,且 People 类中可省略 set 方法,前提是自动装配的属性在 IOC 容器中存在,且符合类型byType!
@Autowired(required = false) 说明这个对象可为null,否则不允许为空,或者使用 @Nullable 注解
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="cat" class="com.wang.pojo.Cat"/>
<bean id="dog" class="com.wang.pojo.Dog"/>
<bean id="people" class="com.wang.pojo.People"/>
</beans>
public class People {
@Autowired
private Dog dog;
@Autowired
private Cat cat;
private String name;
}
@Autowired 先根据 byType 进行注入,如果容器中有多个满足类型的实例,就会根据 byName 进行注入,并不是单纯只根据类型注入,@Resource 默认按照 byName 实现,找不到名字再通过 byType 实现
@Autowired
@Qualifier(value = "cat1")
private Cat cat;
<bean id="cat1" class="com.wang.pojo.Cat"/>
注解开发
注解开发必须导入 aop 包,导入 context 约束, 增加注解的支持
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.wang.pojo"/>
<context:annotation-config/>
</beans>
自动装配注解
@Autowired:自动装配通过 Type,然后 Name,若属性不唯一,可搭配 @Qualifier (value = "xxx")
@Nullable:允许该属性为 Null 空值
@Resource:自动装配通过 Name,然后 Type
衍生注解:
pojo 中 @Component
dao 中 @Repository
service 中 @Service
controller 中 @Controller
上述四个注解代表将 某个类 注册到 Spring 中,装配 bean,只需要在 xml 中配置:
<context:component-scan base-package="com.wang"/>作用域注解:@Scope("singleton")
属性赋值:@Value("王")
用java配置Spring
-
编写 java 文件,添加 @Configuration 注解 和 @Bean 注解,Configuration 本质是一个 Component
package com.wang.config; import com.wang.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyConfig { @Bean public User getUser(){ return new User(); } } -
为实体类添加 @Component 表示被 Spring 托管,@Value("xxx") 给属性赋值
package com.wang.pojo; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component public class User { private String name; public String getName() { return name; } @Value("xx") public void setName(String name) { this.name = name; } } -
测试类实现
import com.wang.config.MyConfig; import com.wang.pojo.User; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); User user = (User) context.getBean("getUser"); System.out.println(user.getName()); } } 上述不准确,有两种配置方式:1:只在类前面加 @Bean 注解,通过 getBean("getUser") 获取对象;2:在配置类前加 @Configuration 和 @ComponentScan(basePackages = "com.wang.pojo"),并且在实体类添加 @Component 注解,通过 getBean("user") 获取对象
动态代理:
基于接口的动态代理:JDK 动态代理
基于类的动态代理:cglib
java 字节码实现:JAVAssist
Proxy、InvocationHandler 调用处理程序
Proxy 提供创建动态代理类和实例的静态方法
InvocationHandler 处理代理实例,创建其代理的接口中相对应的方法,并返回结果
一个动态代理类代理的是一个接口,一般对应一类业务,可实现多个类的代理
package com.wang.demo1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyNew implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(rent, args);
return invoke;
}
}
// 主程序
package com.wang.demo1;
public class Client {
public static void main(String[] args) {
Rent rent = new Host();
// Proxy proxy = new Proxy();
// proxy.setHost(rent);
// proxy.rent();
ProxyNew proxyNew = new ProxyNew();
proxyNew.setRent(rent);
Rent proxy = (Rent) proxyNew.getProxy();
proxy.rent();
}
}
AOP
-
添加依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
<scope>runtime</scope>
</dependency>
</dependencies>
-
编写 UserService 接口 及其 实现类 UserServiceImpl,编写 前置日志 和 后置日志 的类,如下:
package com.wang.service;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class LogBefore implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了!");
}
}
package com.wang.service;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class LogAfter implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+"执行完毕,返回值为"+ returnValue);
}
}
-
在Spring 中配置Bean,配置 aop
execution:[访问修饰符] 方法返回值 包名.类名.方法名(方法的参数)
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config/>
<bean id="userService" class="com.wang.service.UserServiceImpl"/>
<bean id="logBefore" class="com.wang.service.LogBefore"/>
<bean id="logAfter" class="com.wang.service.LogAfter"/>
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="logBefore" pointcut-ref="pc"/>
<aop:advisor advice-ref="logAfter" pointcut-ref="pc"/>
</aop:config>
</beans>
还可以自定义切面,配置 aop,自定义类需要配置Bean
package com.wang.service;
public class diy {
public void before(){
System.out.println("======开始======");
}
public void after(){
System.out.println("======结束======");
}
}
<bean id="diy" class="com.wang.service.diy"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="pc1" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="pc1"/>
<aop:after method="after" pointcut-ref="pc1"/>
</aop:aspect>
</aop:config>
还可以直接在类上加 @Aspect,方法上加 @Before("execution(.....)") 或者 @After (切入点),只需要在 xml 中配置 Bean,以及开启注解支持 < aop:aspectj-autoproxy/ >
<aop:aspectj-autoproxy/>
<bean id="diy2" class="com.wang.service.diy2"/>
package com.wang.service;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class diy2 {
@Before("execution(* com.wang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("======开始======");
}
@After("execution(* com.wang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("======结束======");
}
@Around("execution(* com.wang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint pj) throws Throwable {
System.out.println("环绕前");
System.out.println(pj.getSignature());
pj.proceed();
System.out.println("环绕后");
}
}
综上,一共3种,为使用Spring的API接口实现、自定义来实现AOP(定义切面)、注解实现
整合Mybatis
建立 Spring 配置文件,配置 dataSource 和 sqlSessionFactory
<!--配置 dataSource-->
<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?useUnicode=true&characterEncoding=utf8&useSSL=true"/>
<property name="username" value="root"/>
<property name="password" value="wzf"/>
</bean>
<!--配置 sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/wang/mapper/*.xml"/>
</bean>
需要给接口加一个实现类,为了调用 dao 的方法,在 Spring 中 注册 sqlSession,构造函数注入 sqlSessionFactory,注册 PeopleMapper,注入sqlSession,如下所示:
public class PeopleMapperImpl implements PeopleMapper{
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<People> query() {
PeopleMapper mapper = sqlSession.getMapper(PeopleMapper.class);
return mapper.query();
}
}
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<bean id="PeopleMapper" class="com.wang.mapper.PeopleMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
也可以加一个实现类,在实现接口的基础上,继承父类 SqlSessionDaoSupport,这样就只需要在 Spring 中注册PeopleMapper2,并注入 sqlSessionFactory,如下:
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class PeopleMapperImpl2 extends SqlSessionDaoSupport implements PeopleMapper{
public List<People> query() {
PeopleMapper mapper = getSqlSession().getMapper(PeopleMapper.class);
return mapper.query();
}
}
<bean id="PeopleMapper2" class="com.wang.mapper.PeopleMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
事务管理
声明式事务(AOP)
编程式事务 (改变原有代码)
一般用声明式事务,可以在不改变原有代码情况下实现事务,首先配置 transcationManager,再结合 AOP 实现事务的织入
<bean id="transcationManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
然后配置事务通知,包括给哪些方法配置事务,配置事务的传播属性
<tx:advice id="txAdvice" transaction-manager="transcationManager">
<tx:attributes>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
然后配置事务切入
<aop:config>
<aop:pointcut id="txPc" expression="execution(* com.wang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"/>
</aop:config>
浙公网安备 33010602011771号