一、Spring管理数据源和引入外部文件
1.引入依赖:mysql驱动,数据源
2.内部bean
3.引入外部文件
<!--引入jdbc.properties,之后可以通过${key}的方式访问value-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
二、bean的作用域
scope:设置bean的作用域 scope=“singleton/prototype“ singleton(单例):表示获取该bean所对应的对象都是同一个 prototype(多例):表示获取该bean所对应的对象都不是同一个
三、bean的生命周期
bean的生命周期: * 1.实例化 * 2.依赖注入 * 3.bean对象初始化之前操作(由bean的后置处理器负责)postProcessBeforeInitialization * 4.初始化,需要通过bean的init—method属性指定初始化的方法 * 5.bean对象初始化之后操作(由bean的后置处理器负责)postProcessAfterInitialization * 6.ioc容器关闭时销毁,需要通过bean的destroy—method属性指定销毁的方法
// ConfigurableApplicationContext是 ApplicationContext的子接口,其中拓展了刷新和关闭容器的方法
ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
bean的作用域对生命周期的影响: * 注意:bean的作用域为单例时,生命周期的前三个步骤会在获取IOC容器时执行 * bean的作用域为多例时,生命周期的前三个步骤会在获取bean时执行
四、FactoryBean(区别BeanFactory)
* 其中有三个方法: * 1.getObject():通过一个对象交给IOC容器管理 * 2.getObjectType():设置所提供对象的类型 * 3.isSingleton():所提供的对象是否为单例 * 当FactoryBean的实现类配置为bean时,会将getObject()所返回的对象交给IOC容器管理
、
2.1.2
、
IOC
容器在
Spring
中的实现aaa
Spring
的
IOC
容器就是
IOC
思想的一个落地的产品实现。
IOC
容器中管理的组件也叫做
bean
。在创建
bean
之前,首先需要创建
IOC
容器。
Spring
提供了
IOC
容器的两种实现方式:
①BeanFactory
这是
IOC
容器的基本实现,是
Spring
内部使用的接口。面向
Spring
本身,不提供给开发人员使用。
②
ApplicationContext
BeanFactory
的子接口,提供了更多高级特性。面向
Spring
的使用者,几乎所有场合都使用
ApplicationContext
而不是底层的
BeanFactory
。
五、基于xml的自动装配
* 自动装配: * 根据指定的策略,在IOC容器中匹配某个bean,自动为bean中的类型属性或接口类型的属性赋值 * * 可以通过bean标签中的autowire属性设置自动装配的策略 * 自动装配的策略: * 1.no/default:表示不装配,即bean中的属性不会自动匹配某个bean为属性赋值,此时属性使用默认值 * 2.byType:根据要赋值的属性的类型,在IOC容器中匹配某个bean,为属性赋值 * 注意: * a.若通过类型没有找到任何一个类型匹配的bean,此时不装配,属性使用默认值 * b.若通过类型找到多个类型匹配的bean,此时会抛出异常。 * 总结:当使用byType实现自动装配时,IOC容器中有且只有一个类型匹配的bean能够为属性赋值
* 3.byName;将要赋值的属性的属性名作为bean的id在IOC容器中匹配某个bean,为属性赋值 * 总结:当byType匹配的bean有多个时,此时可以使用byName实现自动装配
六、基于注解管理Bean
1.标识组件的常用注解
@Component
:将类标识为普通组件
@Controller
:将类标识为控制层组件
@Service
:将类标识为业务层组件
@Repository
:将类标识为持久层组件
2.扫描组件
<!--扫描组件--> <!-- context:exclude-filter:排除扫描 type:assignable/annotation annotation:根据注解的类型进行排除,expression需要设置排除的注解的全类名 assignable:根据类的类型进行排除,expression需要设置排除的类的全类名 context:include-filter:包含扫描 注意:需要在context:component-scan标签中设置use-default-filters=“false” use-default-filters="true“(默认)所设置的包下所有的类都需要扫描,此时可以用到排除扫描 use-default-filters="false“所设置的包下所有的类都不需要扫描,此时可以用到包含扫描
<context:component-scan base-package="com.zhou.spring" use-default-filters="false"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="assignable" expression="com.zhou.spring.controller.UserController"/> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
3.bean的id
/通过注解+扫描所配置的bean的id,默认值为类的小驼峰,即类名的首字母为小写的结果 //可以通过标识组件的注解的value属性值设置bean的自定义的id
4.Autowired
//@Autowired:实现自动装配功能的注解 //1.@Autowired能够标识的位置: // a>标识在成员变量上,此时不需要设置成员变量的set方法 // b>标识在set方法上 // c>标识在当前成员变量赋值的有参构造上 // 2.@Autowired的原理: //a>默认通过byType的方式,在IOC容器中通过类型匹配的某个bean为属性赋值 //b>若有多个类型匹配的bean,此时会自动转换为byName的方式实现自动装配 //即将要赋值的属性的属性名作为bean的id匹配某个bean为属性赋值 //c>若byType和byName的方式都无法实现自动装配,即容器中有多个类型匹配的bean //且这些bean的id和要赋值的属性的属性名都不一致,此时抛出异常:NoUniqueBeanDefinitionException //d>此时可以在要赋值的属性上,添加一个注解@Qualifier //通过该注解的value属性值,指定某个bean为属性赋值
//注意:若IOC容器中没有一个类型匹配的bean,此时抛出异常:NoSuchBeanDefinitionException //在@Autowired注解中有个属性required,默认值为true,要求必须完成自动装配 //可以将required设置为false,此时能装配则装配,无法装配则使用属性的默认值
4.动态代理 * (ClassLoader loader:指定加载动态生成的代理类的类加载器 * @NotNull Class[] interfaces:获取目标对象实现的接口的class对象的数组 * @NotNull reflect.InvocationHandler h:设置代理类中的抽象方法该如何重写 * *动态代理有两种: * 1.jdk动态代理,要求必须有接口,最终生成的代理类和目标类实现相同的接口 * 在com.sun.proxy包下,类名为$proxy2 * 2.cglib动态代理,最终生成的代理类继承目标类,并且和目标类在同一包下
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxy(){
ClassLoader classLoader=this.getClass().getClassLoader();
Class<?>[] interfaces=target.getClass().getInterfaces();
InvocationHandler h=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// proxy表示代理对象,method表示要执行的方法,args表示要执行的方法到的参数列表
Object result = method.invoke(target, args);
return result;
}
};
return Proxy.newProxyInstance(classLoader,interfaces,h);
}
}
七、AOP
1.AOP的概念
2.AOP的相关术语
①横切关注点 :目标对象中的非核心关注点
②通知
每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。
③切面
封装通知方法的类。
④目标
被代理的目标对象。
⑤代理
向目标对象应用通知之后创建的代理对象。
⑥连接点
⑦切入点
定位连接点的方式
3.前置通知
<!--AOP的注意事项: 切面类和目标类都需要交给IOC容器管理(注解+扫描) 切面类必须通过@Aspect注解标识为一个切面 在spring的配置文件中设置 <aop:aspectj-autoproxy/>开启基于注解的AOP --> <context:component-scan base-package="com.zhou.spring.aop.annotation"></context:component-scan> <!-- 开启基于注解的AOP--> <aop:aspectj-autoproxy/>
//1.在切面中,需要通过指定的注解将方法表示为通知方法 //@Before:前置通知,在目标方法执行之前执行
@Component
@Aspect
public class LoggerAspect {
@Before("execution(public int com.zhou.spring.aop.annotation.CalculatorImpl.add(int,int))")
public void beforeAdviceMethod(){
System.out.println("LoggerAspect,前置通知");
}
}
4.切入点表达式的语法与重用及获取连接点的信息 //2.切入点表达式:设置在标识通知的注解的value属性中 //@Before("execution(public int com.zhou.spring.aop.annotation.CalculatorImpl.add(int,int))") // @Before("execution(* com.zhou.spring.aop.annotation.CalculatorImpl.*(..))") //第一个*表示任意的访问修饰符和返回值类型,第二个*表示类中任意的方法,..表示任意的参数列表 //3.切入点表达式的重用 //@Pointcut:声明一个重用的切入点表达式 //@Pointcut("execution(* com.zhou.spring.aop.annotation.CalculatorImpl.*(..))") // public void pointCut(){ } //使用方式:@Before("pointCut()") //4.获取连接点的信息:在通知方法的参数位置,设置JoinPoint类型的参数, 获取连接点所对应的方法的签名信息 // Signature signature = joinPoint.getSignature(); 获取连接点所对应的方法的参数 // Object[] args = joinPoint.getArgs();
4.其他通知
//@After():后置通知,在目标对象的finally子句中执行 //@AfterReturning:返回通知,在目标方法返回值之后执行 //@AfterThrowing:异常通知,在目标对象的catch子句中执行
** * 在返回通知中若要获取目标对象方法的返回值,只需要通过@AfterReturning注解的属性returning * 就可以将通知方法的某个参数指定为接收目标对象方法的返回值的参数
@AfterReturning(value = "pointCut()",returning = "result") public void afterReturningAdviceMethod(JoinPoint joinPoint,Object result){ Signature signature = joinPoint.getSignature(); System.out.println("返回通知:"+result);
在异常通知中若要获取目标对象方法的异常,只需要通过@AfterThrowing注解的属性throwing 就可以将通知方法的某个参数指定为接收目标对象方法的异常的参数 */ @AfterThrowing(value = "pointCut()",throwing = "ex") public void afterThrowingAdvice(JoinPoint joinPoint,Throwable ex){ Signature signature = joinPoint.getSignature(); System.out.println("异常通知:"+ex);
5.环绕通知
环绕对象的返回值一定要和目标对象的返回值一致
@Around("pointCut()") public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint){ Object result =null; try { System.out.println("前置"); // 表示目标对象方法的执行 result = joinPoint.proceed(); System.out.println("返回"); } catch (Throwable throwable) { throwable.printStackTrace(); System.out.println("异常"); }finally { System.out.println("后置"); } return result; }
6.切面的优先级
可以通过@Order注解的value属性设置优先级,默认值Integer的最大值
@Order注解的value属性值越小,优先级越高