一、Spring IoC容器补充(1)
Spring IoC容器,DI(依赖注入):
注入的方式:设值方法注入setter(属性注入)/构造子注入(构造函数传入依赖的对象)/字段注入Field(注解)/接口注入 out
装配的方式:手动装配(<property>、<constructor-arg>、@Autowired、@Resource)/自动装配(autowire="byName") 1、装配各种类型的属性
A、简单属性-value属性或者value元素
<bean id="p1" class="cn.itcasg.gz.springioc.Person">
<property name="name" value="张无忌"></property>
<!-- property元素中的内容叫属性值,会自动把value描述的值转换成对应属性的类型 -->
<property name="age"><value>68</value></property>
<!-- 也可以使用value来装配一些Spring支持的类型URL,Class -->
<property name="homePage" value="http://www.itcast.cn"></property>
</beans> B、引用其它bean-使用ref属性或者标签。
<property name="parent">
<!-- ref引用其它的 bean,local表示引用本容器中的bean,parent表示引用父容器中某个bean,bean表示引入某个bean,先在当容器中找,然后再到父容器中找 -->
<ref bean="p0" />
</property> C、内部bean
<property name="parent">
<!-- 值是内部Bean ,一般不需要指定bean的名称 -->
<bean class="cn.itcasg.gz.springioc.Person">
<constructor-arg value="张三丰"></constructor-arg>
</bean>
</property>
D、装配集合
(1)、数组
代码
public void setFavs(String[] favs) {
this.favs = favs;
} 配置
<!-- 装配数组 -->
<property name="favs">
<array>
<value>足球</value>
<value>蓝球</value>
<value>音乐</value>
</array>
</property> (2)、list
代码
public void setSchools(List<String> schools) {
this.schools = schools;
} 配置
<property name="schools">
<list>
<value>北大</value>
<value>清华</value>
</list>
</property> (3)、set
public void setCitys(Set<String> citys) {
this.citys = citys;
} <property name="citys">
<set>
<value>广州</value>
<value>北京</value>
<value>西安</value>
<value>广州</value> </set>
</property> D、装配Map public void setScores(Map<String, Double> scores) {
this.scores = scores;
}
<property name="scores">
<map>
<entry key="语文" value="50"></entry>
<entry key="数学" value="30"></entry>
<entry key="历史" value="20"></entry>
<!-- key-ref,value-ref属性用来引用其它bean -->
</map>
</property> E、装配Properties
public void setIms(Properties ims) {
this.ims = ims;
} <!-- 装配属性类型 -->
<!--
<property name="ims">
<props>
<prop key="qq">4858458</prop>
<prop key="msn">caishiyou@sina.com</prop>
</props>
</property> -->
<!-- 在value中直接使用键值对来作为属性内容 -->
<property name="ims">
<value>
qq=58568565868
msn=kdkdkf@ddd.com
</value>
</property> F、装配空值null <property name="age">
<!-- null标签用来指定空值 -->
<null/>
</property> 2、注解装配解决方案1(XML+注解配合)
xml用来定义Bean的信息;注解用来配置依赖信息。 (1)、在配置文件中配置bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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-3.0.xsd
"> <!-- 开启注解配置 -->
<context:annotation-config/>
<bean id="personDao" class="cn.itcasg.gz.springioc.PersonDaoImpl">
</bean>
<bean id="personDao2" class="cn.itcasg.gz.springioc.PersonDaoImpl">
</bean> <bean id="dao" class="cn.itcasg.gz.springioc.Person">
</bean> <bean id="personService" class="cn.itcasg.gz.springioc.PersonServiceImpl">
</bean> </beans>
(2)、在JavaBean中用注解来指定依赖注入
@Resource(Java标签的资源注解),@Autowired(Spring自定的注解),注解可以加在setter方法上(setter注入)/可以加在Field上(Field注入)。
@Autowired--按类型注入。required=false用来指定该依赖的对象是否是必须的。
@Resource--按名字注入,找到名字相同,则直接注入。找不到名字相同,则找类型。可能在@Resource使用name属性来指定要注入的Bean的名称。
@Qualifier("personDao2")--用来指定要注入的Bean叫什么名字,与@Autowired配合使用。 代码:
public class PersonServiceImpl implements IPersonService { private IPersonDao dao;
//@Resource(name="personDao2")
@Autowired
@Qualifier("personDao2")
public void setDao(IPersonDao dao) {
System.out.println("setDao()...");
this.dao = dao;
} 推荐使用@Resource (3)、在配置文件中开启注解扫描
<!-- 开启注解配置 -->
<context:annotation-config/> 3、使用注解方案2,完全使用注解---(掌握)
(1)、如何指定哪些业务组件是需要放到Spring容器中管理的--
A、在实现类上添加注解:@Repository(持久层组件)、@Service(业务层的组件)、@Controller(控件层组件)、@Component(不知道哪一层就用他) 。 @Repository("personDao")
public class PersonDaoImpl2 implements IPersonDao {
} 如何指定Bean的名称:默认的Bean名称会是类名首字母变小写,使用value属性就可以指定具体的Bean名称。 Bean的作用域:默认是单例singleton。其它作用域,则使用@Scope标签来指定。比如:
@Controller("personAction")
@Scope("prototype")
public class PersonAction{
} B、在配置文件中使用<context:component-scan>指定让Spring去扫描哪些包
<context:component-scan base-package="cn.itcasg.gz,cn.itcasg.bj"></context:component-scan> (2)、给组件指定依赖--使用@Autowire或@Resource标签 @Resource(name="personDao")
public void setDao(IPersonDao dao) {
} 二、Spring IOC补充(2)
1、自定义属性--如果使用value来注入非简单类型的对象
只要依赖的对象他有一个只带一个参数(并且类型为String)的构造函数,他就可以转换。
A、自定义类型编辑器--PropertyEditorSupport public class MyDateEditor extends PropertyEditorSupport {
private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
@Override
public void setAsText(String text) throws IllegalArgumentException {
try {
System.out.println("调用自定义的类型编辑器setAsText()..."+text);
Date date=sdf.parse(text);
setValue(date);
} catch (ParseException e) {
e.printStackTrace();
super.setAsText(text);
}
} } B、在容器中注册类型编辑器 <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" value="cn.itcast.gz.springioc.MyDateEditor"></entry>
</map>
</property>
</bean> 2、容器扩展点及应用--Spring提供了一些接口,让我们通过这些接口可以扩充容器的功能。
(1)、BeanPostProcessor--每一个Bean创建完以后均会执行Processor的相关方法 (2)、 BeanFactoryPostProcessor--当容器把配置信息加载完以后,对象没有初始之前,可以加入自己的功能。 (3)、属性配置,利用容器扩展点来让配置中支持${db.url}类似的表达式,db.url中的值是存在属性文件。
属性文件:db.properties
db.url=jdbc:mysql:///itcast
db.driverClass=my.dd.d.JdbcDiver
db.username=root
db.password=abc Spring配置文件:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="db.properties"></property>
</bean> 简化方案:<context:property-placeholder location="db.properties"/> <bean id="dataSource" class="cn.itcast.gz.springioc.MyDataSource">
<property name="url" value="${db.url}"></property>
<property name="driverClass" value="${db.driverClass}"></property>
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
</bean> 3、工厂bean-FactoryBea--有一种比较特殊的Bean,这种Bean是用来生产各种各样产品的Bean。
A、定义一个生产Person对象的FactoryBean,实现Spring提供的FactoryBean<Person> 接口即可。
public class MyFactoryBean implements FactoryBean<Person> { //要产品的时候,会调用getObject()方法
@Override
public Person getObject() throws Exception {
System.out.println("getObject()...");
return new Person();
} @Override
public Class<Person> getObjectType() {
System.out.println("getObjectType()...");
return null;
} @Override
public boolean isSingleton() {
System.out.println("isSingleton()...");
return true;
} } B、直接在配置文件中配置
<bean id="bean1" class="cn.itcast.gz.springioc.MyFactoryBean"></bean>
bean1的值为由MyFactoryBean的getObject()方法所返回的类型。 4、spring3.0中使用p及c命名空间简化配置 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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-3.0.xsd
">
<bean id="p1" class="cn.itcast.gz.springioc.Person">
<property name="name" value="张无忌"></property>
<property name="age" value="18"></property>
</bean>
<!-- 使用p命名空间以后的方法 -->
<bean id="p2" class="cn.itcast.gz.springioc.Person"
p:name="张无忌" p:age="19"/>
<!-- 使用构造函数 -->
<bean id="p3" class="cn.itcast.gz.springioc.Person">
<constructor-arg value="张三丰"></constructor-arg>
<constructor-arg value="108"></constructor-arg>
</bean> <!-- 使用c命名空间简化构造参数后的方法 -->
<bean id="p4" class="cn.itcast.gz.springioc.Person"
c:name="张三丰" c:age="108" p:parent-ref="p5"
/>
<bean id="p5" class="cn.itcast.gz.springioc.Person"
c:name="张大三"
/>
</beans> 三、代理模式
1、代理模式概述--当客户端不能直接与真实对象打交道或者是需要扩充真实对象的功能又不想修改真实对象的代码时候,需要应用到代理。
抽象主题
真实主题
代理主题 2、JDK动态代理-对接口代理--(掌握)
//真实对象
final IHello realObject=new HelloImpl();
//代理对象
IHello hello=(IHello)Proxy.newProxyInstance(JdkProxyTest.class.getClassLoader(), new Class[]{IHello.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("准备执行"+method.getName()+"--"+new Date());
//代理对象去调用真实对象的相应方法去响应
Object ret=method.invoke(realObject, args);
System.out.println("执行完成!");
return ret;
}
});
hello.sayHello();
System.out.println( hello.toString()); 3、使用第三方框架来实现对类的代理CGLIB,对类代理-(了解)
public void proxyClass(){
final HelloImpl2 realObject=new HelloImpl2();
//使用CGLIB的Enhancer来创建类的代理
Enhancer en=new Enhancer();
en.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object obj, Method method, Object[] args)
throws Throwable {
System.out.println("准备执行"+method.getName()+"--"+new Date());
Object ret=method.invoke(realObject, args);
System.out.println("执行完成!");
return ret;
}
});
//设置父类
en.setSuperclass(HelloImpl2.class);
//创建出类的代理对象
HelloImpl2 hello=(HelloImpl2) en.create();
//调用代理对象上的方法,均分去执行Callback里面指定的invoke方法
hello.sayHello();
System.out.println(hello);
System.out.println(hello.getClass());
} 四、AOP概念及框架原理--(掌握) 1、AOP的应用场景-->OOP
Aspect-切面(方面)
当解决某一方面的问题的相同的代码零零散散的分布核心业务方法中。造成代码很难维护。 2、传统解决横切性质问题的代码
public class PersonDaoImpl implements IPersonDao {
@Override
public void save(Person p) {
//切面2:记录日志
System.out.println(UserContext.getUser()+"准备调用save方法,时间:"+new Date());
//切面1:安全性问题的代码
if(!"admin".equals(UserContext.getUser())){
new RuntimeException("没有权限!");
}
// 核心业务逻辑
System.out.println("执行添加:insert into person...."); //切面3:审核功能
System.out.println(UserContext.getUser()+"成功调用save方法,时间:"+new Date()); } @Override
public void update(Long id, Person p) {
//切面2:记录日志
System.out.println(UserContext.getUser()+"准备调用save方法,时间:"+new Date()); //切面1:安全性问题的代码
if(!"admin".equals(UserContext.getUser())){
new RuntimeException("没有权限!");
}
System.out.println("执行修改:update into person...."); //切面3:审核功能
System.out.println(UserContext.getUser()+"成功调用save方法,时间:"+new Date()); } @Override
public void delete(Long id) {
//切面2:记录日志
System.out.println(UserContext.getUser()+"准备调用save方法,时间:"+new Date()); //切面1:安全性问题的代码
if(!"admin".equals(UserContext.getUser())){
new RuntimeException("没有权限!");
}
System.out.println("执行删除:delete into person...."); //切面3:审核功能
System.out.println(UserContext.getUser()+"成功调用save方法,时间:"+new Date()); } }
3、使用AOP的解决方案--织入
A、切面1
public class SercurityAscpect { public void checkPermission(Method method){
//切面1:安全性问题的代码
System.out.println("执行权限检查....");
if(!"admin".equals(UserContext.getUser())){
throw new RuntimeException("没有权限!");
}
}
} B、切面2
public class WirteLogAspect {
public void writeBeforeLog(Method method){
//切面2:记录日志
System.out.println(UserContext.getUser()+"准备调用"+method.getName()+"方法,时间:"+new Date());
}
public void writAfterLog(Method method){
//切面3:审计功能
System.out.println(UserContext.getUser()+"成功调用"+method.getName()+"方法,时间:"+new Date());
}
} C、核心业务逻辑(切面3) public class PersonDaoImpl implements IPersonDao {
@Override
public void save(Person p) {
// 核心业务逻辑
System.out.println("执行添加:insert into person...."); } @Override
public void update(Long id, Person p) {
System.out.println("执行修改:update into person...."); } @Override
public void delete(Long id) {
System.out.println("执行删除:delete into person...."); } }
4、AOP框架实现-借助IoC容器,使用代理技术,解析配置文件生成不同的代理对象。
public void aop() throws Exception{
//读到配置信息
//personDao.after=writeLogAscpect.writfterLog
//得到容器中personDao的Bean.
//创建一个personDao这个Bean一个代理对象
//InvocationHalder对象的invoke方法中
//1\先调用真实对象的方法。
//2\调用writeLogAscpect这个切面Bean的writAfterLog方法
//3\返回
//把代理对象存到容器
Properties properties = new Properties();
properties.load(ContainerImpl.class.getResourceAsStream("/aop.properties"));
//循环获得所有key
for(Object item:properties.keySet()){
//personDao.before=sercurityAspect.checkPermission,writeLogAscpect.writeBeforeLog
final String key=item.toString();
String value=properties.getProperty(key); //获得Bean的名称
String beanName=key.substring(0,key.indexOf('.')); String[] vs=value.split(",");
for(final String v:vs){
//得到要创建代理的对象
final Object bean=getBean(beanName);
//sercurityAspect.checkPermission
//给bean创建一个代理
//检测Bean有没有实现接口
if(bean.getClass().getInterfaces().length>0){
//使用JDK动态代理来创建代理
Object proxyBean=Proxy.newProxyInstance(this.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//v=sercurityAspect.checkPermission
//获得切面Bean,及切面方法
String aspectBeanName=v.substring(0,v.indexOf('.'));
String aspectMethodName=v.substring(v.indexOf('.')+1);
Object aspectBean=getBean(aspectBeanName);
//找到一个public而且只带一个(Method)类型参数,并且名称是aspectMethodName的方法
Method aspectMethod=aspectBean.getClass().getMethod(aspectMethodName, Method.class);
if(key.indexOf(".before")>0){
//执行切面Bean上的aspectMethod方法
aspectMethod.invoke(aspectBean,method);
}
//调用真实对象上的method方法
Object ret=method.invoke(bean, args);
if(key.indexOf(".after")>0){
//执行切面Bean上的aspectMethod方法
aspectMethod.invoke(aspectBean,method);
}
return ret;
}
});
//把代理Bean给保存到缓存中
beans.put(beanName, proxyBean);
}
else {
//使用其它技术来创建代理
}
}
}
}

[Spring学习笔记 4 ] AOP 概念原理以及java动态代理的更多相关文章

  1. Spring学习笔记之aop动态代理(3)

    Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...

  2. spring AOP底层原理实现——jdk动态代理

    spring AOP底层原理实现——jdk动态代理

  3. AOP面向切面编程JAVA动态代理实现用户权限管理(实现篇)

    java动态代理机制的功能十分强大,使用动态代理技术能够有效的降低应用中各个对象之间的耦合紧密程度,提高开发的效率以及程序的可维护性,事实上Spring AOP就是建立在Java动态代理的基础之上.其 ...

  4. Spring学习笔记2—AOP

    1.AOP概念 AOP(Aspect Oriented Programming):面向切面编程,AOP能够将那些与业务无关,却为业务模块所共同调用的应用(例如事务处理.日志管理.权限控制等)封装起来, ...

  5. Spring学习笔记4——AOP

    AOP 即 Aspect Oriented Program 面向切面编程 首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能. 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务 ...

  6. Spring学习笔记之AOP配置篇(一)

    [TOC] 1. 创建并声明一个切面 首先,创建一个类,添加@Component注解使其添加到IoC容器 然后,添加@Aspect注解,使其成为一个切面 最后,在配置文件里面,使用<aop:as ...

  7. 【初学Java学习笔记】AOP与OOP

    AOP(Aspect Oriented Programming) 面向切面编程,是属于Spring框架中的内容.AOP相当于OOP的补充,当我们需要对多个对象引入一个公共行为,比如日志,操作记录等,就 ...

  8. Spring源码剖析5:JDK和cglib动态代理原理详解

    AOP的基础是Java动态代理,了解和使用两种动态代理能让我们更好地理解 AOP,在讲解AOP之前,让我们先来看看Java动态代理的使用方式以及底层实现原理. 转自https://www.jiansh ...

  9. Spring学习笔记(四)—— Spring中的AOP

    一.AOP概述 AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.O ...

随机推荐

  1. 云服务器 ECS Linux Ubuntu 主机修改主机名

    云服务器 ECS Linux 主机修改主机名 修改云服务器 ECS Linux 主机名常见的有两种方式,本文对此进行概要说明. 临时生效修改 使用命令行修改 hostname 主机名(可自定义),重新 ...

  2. chrome浏览器直接编辑源码功能的开通办法 - Chrome Workspace

    因为我看到网上有些文章的教程已经过时,特更新,此文章的步骤适用于chrome 或 chromium 30或31. 开启”开发者工具实验”(这翻译真心烂…): 在browser输入chrome://fl ...

  3. Android 分析 Android 应用结构

    本文说明 Android 项目组成,虽然简单,但决不能忽视. 当你从简单 Hello World 程序,到会实现一些常见功能,比如,下拉(上拉)刷新最新(加载更多),消息处理(UI 通知更新),Vie ...

  4. redis-dev

    redis install by centos   -------------------------------------------------------------------------- ...

  5. 视频播放代码 crastr3

    下载:http://down.51cto.com/data/1904974 代码(亲测): <html xmlns="http://www.w3.org/1999/xhtml" ...

  6. mahout基于Hadoop的CF代码分析(转)

    来自:http://www.codesky.net/article/201206/171862.html mahout的taste框架是协同过滤算法的实现.它支持DataModel,如文件.数据库.N ...

  7. VB 求余求整

    可以直接用函数来实现: 1.用CInt()函数的范围在-32,768 至 32,767,对于小数部分四舍五入 . 2.用Int()函数和Fix()函数都会删除参数的小数部份而返回剩下的整数, 不同之处 ...

  8. 行内元素有哪些?块级元素有哪些? 空(void)元素有那些?

    行内元素:a.b.span.img.input.strong.select.label.em.button.textarea块级元素:div.ul.li.dl.dt.dd.p.h1-h6.blockq ...

  9. 【超精简JS模版库/前端模板库】原理简析 和 XSS防范

    使用jsp.php.asp或者后来的struts等等的朋友,不一定知道什么是模版,但一定很清楚这样的开发方式: <div class="m-carousel"> < ...

  10. [pip]安装和管理python第三方包

    使用 ”pip install 包名“   直接下载安装第三方包 1.在以下地址下载最新的PIP安装文件:http://pypi.python.org/pypi/pip#downloads2.下载Wi ...