spring-context.xml
"car" class="com.yt.model.Car" init-method="init" destroy-method="destroy"/>
Car类
public class Car {
public Car() {
System.out.println("car Constructor");
}
public void init() {
System.out.println("car ... init");
}
public void destroy() {
System.out.println("car ... destroy");
}
}
在调用构造器方法后,调用初始化方法init(),当容器关闭时调用销毁方法destroy()。
public class Cat implements InitializingBean,DisposableBean {
public Cat() {
System.out.println("cat constructor");
}
/**
* 在初始化属性赋值之后调用该方法
*/
public void afterPropertiesSet() throws Exception {
System.out.println("cat ... afterPropertiesSet");
}
public void destroy() throws Exception {
System.out.println("cat destroy");
}
}
该方式实现的生命周期与spring容器的接口耦合,不推荐使用。
实现BeanPostProcessor接口并注册到IOC容器中,IOC会在初始化每一个bean前后调用该接口相应的方法,当有多个BeanPostProcessor实现时,可以用@Order指定加载顺序。
@Component
@Order(value = 1)
public class MyBeanPostProcessor implements BeanPostProcessor{
/**
* @param bean
* @param beanName
* @return 返回原来的bean或包装过的bean
* @throws BeansException
*/
//初始化前调用,在afterPropertiesSet和init-method方法前
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean +"-----"+ beanName+"---beforeInit");
return bean;
}
//初始化后调用,在afterPropertiesSet和init-method方法之后
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean + "-----" + beanName+"---afterInit");
return bean;
}
}
@Configuration
public class MainConfigLifeCycle {
/**
* 初始化:对象创建完成,并赋值后,调用初始化方法
* 销毁:
* singleton:容器关闭时调用
* prototype:容器不会管理这个bean,容器不会调用销毁方法
* @return
*/
@Bean(initMethod = "init",destroyMethod = "destroy")
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public Car car() {
return new Car();
}
}
public class Car {
public Car() {
System.out.println("car Constructor");
}
@PostConstruct
public void init() {
System.out.println("car ... init");
}
@PreDestroy
public void destroy() {
System.out.println("car ... destroy");
}
}
为同一个bean配置多个生命周期机制,不同的初始化方法,调用如下:
析构方法调用顺序是相同的:
property-placeholder location="classpath:jdbc.properties" order="1"/>
property-placeholder location="classpath:variable.properties" order="2"/>
id="dataSourece" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}"/>
<property name="jdbcUrl" value="${url}"/>
<property name="user" value="${userName}"/>
<property name="password" value="${password}"/>
@PropertySources({
@PropertySource(value = {"classpath:variable.properties"}),
@PropertySource(value = "classpath:jdbc.properties")
})
@Configuration
@ComponentScan(value = {"com.yt.conf.value"})
public class MainConfigValue {
}
@PropertySources中可定义多个@PropertySource,也可以单独定义多个@PropertySource
@Component
public class Pig {
@Value("张三")
private String name;
@Value("#{20-1}") //SpEl表达式
private int age;
@Value("${userName}") //properties属性文件引入
private String phone;
}
@value可以给属性、参数、方法赋值,值可以是字符串、SpEL和EL表达式。
//注解在字段上
@Autowired(required = true)
private Custom custom;
//注解在有参构造器上
@Autowired
public CustomDao(Custom custom) {
this.custom = custom;
}
//注解在set方法上
@Autowired
public void setCustom(Custom custom) {
this.custom = custom;
}
@Autowired:优先根据类型去容器中查找,如果有多个则根据属性名去查找,required 默认为true,当required=false时可以找不到装配的实例。
@Qualifier指定需要装配的组件的id
@Autowired(required = true)
@Qualifier("customService1")
private CustomService customService;
当有多个同类型的bean被自动装配时,注解了@Primary的bean会被优先装配。
@Resource与@Autowired注解类似,都可以实现自动装配,区别在于@Resource是默认是根据name作为id装配,并且不可结合@Quaifier、@Primary使用
和Autowired功能一样,区别在于缺少Autowired的required属性
使用@profile注解的bean只有在被激活时才会被加载,默认为”default”,可以利用此注解控制测试、开发和生产三种不同环境中bean的加载。
-VM options:-Dspring.profiles.active=test
@Configuration
@PropertySource(value="classpath:jdbc.properties")
public class ProfileConfig implements EmbeddedValueResolverAware{
StringValueResolver resolver;
private String driverClass;
@Value("${userName}")
private String user;
@Bean
@Profile(value = "test")
public DataSource testDataSource(@Value("${password}")String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setJdbcUrl("${url}");
dataSource.setDriverClass(driverClass);
dataSource.setPassword(pwd);
System.out.println("test"+pwd);
return dataSource;
}
@Bean
@Profile(value = "dev")
public DataSource devDataSource(@Value("${password}")String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setJdbcUrl("${url}");
dataSource.setDriverClass(driverClass);
dataSource.setPassword(pwd);
System.out.println("dev"+pwd);
return dataSource;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.resolver = resolver;
driverClass = resolver.resolveStringValue("${driverClass}");
}
}
容器管理的Bean一般不需要了解容器的状态和直接使用容器,但是在某些情况下,是需要在Bean中直接对IOC容器进行操作的,这时候,就需要在Bean中设定对容器的感知,Spring IOC容器也提供了该功能,它是通过特定的Aware接口来完成的。
Aware | 作用 |
---|---|
BeanNameAware | 可以在Bean中得到它在IOC容器中的Bean的实例的名字 |
BeanFactoryAware | 可以在Bean中得到Bean所在的IOC容器BeanFactory,从而直接在Bean中使用IOC容器的服务 |
ApplicationContextAware | 可以在Bean中得到Bean所在的应用上下文ApplicationContext,从而直接在Bean中使用上下文的服务 |
MessageSourceAware | 在Bean中可以得到消息源 |
ApplicationEventPublisherAware | 在bean中可以得到应用上下文的事件发布器,从而可以在Bean中发布应用上下文的事件 |
ResourceLoaderAware | 在Bean中可以得到ResourceLoader,从而在bean中使用ResourceLoader加载外部对应的Resource资源 |
EnvironmentAware | 在Bean中得到Environment,从而在Bean中设置上下文环境 |
EmbeddedValueResolverAware | 在Bean中得到StringValueResolver,从而在Bean中解析EL或SpEL表达式值 |
ImportAware | 在Bean中得到AnnotationMetadata |
ServletConfigAware | 在Bean中得到ServletConfig |
LoadTimeWeaverAware | 在Bean中得到LoadTimeWeaver |
BeanClassLoaderAware | 在Bean中得到ClassLoader |
ServletContextAware | 在Bean中得到ServletContext |
每个Aware接口都有对应的BeanPostProcessor实现。实现Aware接口的每个bean被初始化前后都会有相应的BeanPostProcessor被匹配,这些BeanPostProcessor会调用该bean实现了Aware接口的方法,这些方法都是set方法。示例如@Profile中实现了EmbeddedValueResolverAware接口的类可以通过setEmbeddedValueResolver方法获取StringValueResolver实例。
JDK的代理是必须要实现接口的,CGLIB代理是生成的目标类的子类,所以类和方法不能声明为final的,要不然就会有问题,spring中默认使用jdk 的动态代理(实现接口了),除强制设置CGLIB的代理
Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object proxy,Method method, Object[] args)。在实际使用时,第一个参数proxy一般是指代理类,method是被代理的方法,args为该方法的参数数组。
Proxy : 该类即为动态代理类
接口和被代理类
public interface Arithmetic {
public int add(int a,int b);
public int division(int a,int b);
}
@Repository
public class ArithmeticImpl implements Arithmetic{
public int add(int a,int b){
System.out.println(a+b);
return a+b;
}
public int division(int a,int b){
System.out.println(a/b);
return a/b;
}
}
JDK代理工厂
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
super();
this.target = target;
}
//给目标对象生成代理对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
//回调方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println("method="+methodName);
Object returnValue = method.invoke(target, args);
System.out.println("result="+returnValue);
return returnValue;
}
});
}
}
测试
public class ProxyTest {
public static void main(String[] args) {
Arithmetic arithmetic = new ArithmeticImpl();
//获取代理类
ProxyFactory proxyFactory = new ProxyFactory(arithmetic);
Arithmetic proxy = (Arithmetic )proxyFactory.getProxyInstance();
int resutl = proxy.add(1, 2);
}
}
CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。 当然这些实际的功能是asm所提供的,asm又是什么?Java字节码操控框架,ASM是一套java字节码生成架构,它可以动态生成二进制格式的stub类或其它代理类,或者在类被java虚拟机装入内存之前,动态修改类。实际上CGlib为spring aop提供了底层的一种实现;为hibernate使用cglib动态生成VO/PO (接口层对象)
public class CglibProxyFactory implements MethodInterceptor{
private Object target;
public CglibProxyFactory(Object target) {
super();
this.target = target;
}
public Object getProxyInstance(){
//工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(target.getClass());
//设置回调函数
en.setCallback(this);
//创建子类(代理对象)
return en.create();
}
//回调方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String methodName = method.getName();
System.out.println("method="+methodName);
Object returnValue = method.invoke(target, args);
System.out.println("result="+returnValue);
return returnValue;
}
}
<aop:aspectj-autoproxy/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.yt.aop.*.*(int,int))"/>
<aop:aspect ref="arithmeticAspect" order="1">
<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
<aop:after method="afterMethod" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
aop:aspect>
aop:config>
开启AOP
@EnableAspectJAutoProxy
public class MainConfig {
}
配置切面类
@Aspect
@Order(value = 2)
public class ArithmeticAspect {
/**
* 定义一个方法,用于声明切入点表达式,一般该方法中不需要添加其他代码
*/
@Pointcut("execution(* com.yt.aop.*.*(int,int))")
public void declareJoinPointExpression(){}
/**
* 前置通知:方法执行之前执行
* @param joinPoint
*/
@Before("declareJoinPointExpression()")
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
List
@EnableAspectJAutoProxy开启AOP功能,首先从@EnableAspectJAutoProxy看起:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
}
由上可以看出@EnableAspectJAutoProxy 导入了组件AspectJAutoProxyRegistrar,而查看源代码可知AspectJAutoProxyRegistrar是ImportBeanDefinitionRegistrar的实现类,ImportBeanDefinitionRegistrar通过BeanDefinitionRegistry注册组件,关于ImportBeanDefinitionRegistrar的示例详见 Spring基于xml配置与注解驱动开发(一)。
BeanDefinitionRegistry注册了AnnotationAwareAspectJAutoProxyCreator
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
由以上继承树发现AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor、Aware和Ordered接口。
未完待续。。。。。。。。。。